Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15ee34c48b | |||
| f62218c9fb | |||
| fee93cd921 | |||
| d58549b96b | |||
| 4d87675eb7 | |||
| 3632fd1d16 | |||
| e74332752f | |||
| 2d37aadc77 | |||
| 18890aa83a | |||
| c658773061 | |||
| 5dbab9062c |
@@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "[pre-commit] Running cargo fmt --all" >&2
|
||||
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
echo "[pre-commit] cargo not found in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cargo fmt --all
|
||||
|
||||
# Stage any Rust files that were reformatted
|
||||
changed=$(git diff --name-only --diff-filter=M | grep -E '\\.rs$' || true)
|
||||
if [ -n "$changed" ]; then
|
||||
echo "$changed" | xargs git add
|
||||
echo "[pre-commit] Added formatted files" >&2
|
||||
fi
|
||||
|
||||
# Fail if further diffs remain (shouldn't happen normally)
|
||||
unfmt=$(git diff --name-only --diff-filter=M | grep -E '\\.rs$' || true)
|
||||
if [ -n "$unfmt" ]; then
|
||||
echo "[pre-commit] Some Rust files still differ after formatting:" >&2
|
||||
echo "$unfmt" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -1,129 +0,0 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy, rustfmt
|
||||
- name: Install system dependencies (Linux)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get update && sudo apt-get install -y libdrm-dev libdrm-amdgpu1
|
||||
- name: Cargo fmt
|
||||
run: cargo fmt --all -- --check
|
||||
- name: Clippy
|
||||
run: cargo clippy --all-targets --all-features -- -D warnings
|
||||
- name: Build (release)
|
||||
run: cargo build --release --workspace
|
||||
|
||||
- name: "Linux: start agent and run WS probe"
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
RUST_LOG=info SOCKTOP_ENABLE_SSL=0 SOCKTOP_AGENT_GPU=0 SOCKTOP_AGENT_TEMP=0 ./target/release/socktop_agent -p 3000 > agent.log 2>&1 &
|
||||
AGENT_PID=$!
|
||||
for i in {1..60}; do
|
||||
if curl -fsS http://127.0.0.1:3000/healthz >/dev/null; then break; fi
|
||||
sleep 1
|
||||
done
|
||||
if ! curl -fsS http://127.0.0.1:3000/healthz >/dev/null; then
|
||||
echo "--- agent.log (tail) ---"
|
||||
tail -n 200 agent.log || true
|
||||
(command -v ss >/dev/null && ss -ltnp || netstat -ltnp) || true
|
||||
kill $AGENT_PID || true
|
||||
exit 1
|
||||
fi
|
||||
SOCKTOP_WS=ws://127.0.0.1:3000/ws cargo test -p socktop --test ws_probe -- --nocapture
|
||||
kill $AGENT_PID || true
|
||||
|
||||
- name: "Windows: start agent and run WS probe"
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$env:SOCKTOP_ENABLE_SSL = "0"
|
||||
$env:SOCKTOP_AGENT_GPU = "0"
|
||||
$env:SOCKTOP_AGENT_TEMP = "0"
|
||||
$out = Join-Path $PWD "agent.out.txt"
|
||||
$err = Join-Path $PWD "agent.err.txt"
|
||||
$p = Start-Process -FilePath "${PWD}\target\release\socktop_agent.exe" -ArgumentList "-p 3000" -RedirectStandardOutput $out -RedirectStandardError $err -PassThru -NoNewWindow
|
||||
$ready = $false
|
||||
for ($i = 0; $i -lt 60; $i++) {
|
||||
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$pinfo.FileName = "curl.exe"
|
||||
$pinfo.Arguments = "-fsS http://127.0.0.1:3000/healthz"
|
||||
$pinfo.RedirectStandardOutput = $true
|
||||
$pinfo.RedirectStandardError = $true
|
||||
$pinfo.UseShellExecute = $false
|
||||
$proc = [System.Diagnostics.Process]::Start($pinfo)
|
||||
$proc.WaitForExit()
|
||||
if ($proc.ExitCode -eq 0) { $ready = $true; break }
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
if (-not $ready) {
|
||||
Write-Warning "TCP connect to (127.0.0.1 : 3000) failed"
|
||||
if (Test-Path $out) { Write-Host "--- agent.out (full) ---"; Get-Content $out }
|
||||
if (Test-Path $err) { Write-Host "--- agent.err (full) ---"; Get-Content $err }
|
||||
Write-Host "--- netstat ---"
|
||||
netstat -ano | Select-String ":3000" | ForEach-Object { $_.Line }
|
||||
if ($p -and !$p.HasExited) { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue }
|
||||
throw "agent did not become ready"
|
||||
}
|
||||
$env:SOCKTOP_WS = "ws://127.0.0.1:3000/ws"
|
||||
try {
|
||||
cargo test -p socktop --test ws_probe -- --nocapture
|
||||
} finally {
|
||||
if ($p -and !$p.HasExited) { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue }
|
||||
}
|
||||
|
||||
- name: Smoke test (client --help)
|
||||
run: cargo run -p socktop -- --help
|
||||
|
||||
- name: Package artifacts (Linux)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p dist
|
||||
cp target/release/socktop dist/
|
||||
cp target/release/socktop_agent dist/
|
||||
tar czf socktop-${{ matrix.os }}.tar.gz -C dist .
|
||||
|
||||
- name: Package artifacts (Windows)
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: pwsh
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force -Path dist | Out-Null
|
||||
Copy-Item target\release\socktop.exe dist\
|
||||
Copy-Item target\release\socktop_agent.exe dist\
|
||||
Compress-Archive -Path dist\* -DestinationPath socktop-${{ matrix.os }}.zip -Force
|
||||
|
||||
- name: Upload build artifacts (ephemeral)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: socktop-${{ matrix.os }}
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.zip
|
||||
|
||||
- name: Upload to rolling GitHub Release (main only)
|
||||
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: latest
|
||||
name: Latest build
|
||||
prerelease: true
|
||||
draft: false
|
||||
files: |
|
||||
*.tar.gz
|
||||
*.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,2 +0,0 @@
|
||||
/target
|
||||
.vscode/
|
||||
@@ -0,0 +1,423 @@
|
||||
# APT Repository Setup Summary
|
||||
|
||||
## 🎉 What You Now Have
|
||||
|
||||
You now have a complete system for creating and hosting your own APT repository for socktop packages, **without needing a sponsor or official Debian/Ubuntu approval**.
|
||||
|
||||
## 📁 Files Created
|
||||
|
||||
### Scripts (in `scripts/`)
|
||||
- **`init-apt-repo.sh`** - Initializes the APT repository directory structure
|
||||
- **`add-package-to-repo.sh`** - Adds .deb packages to the repository and generates metadata
|
||||
- **`sign-apt-repo.sh`** - Signs the repository with your GPG key
|
||||
- **`setup-apt-repo.sh`** - All-in-one interactive wizard to set everything up
|
||||
|
||||
### Documentation
|
||||
- **`QUICK_START_APT_REPO.md`** - Quick start guide (< 10 minutes)
|
||||
- **`docs/APT_REPOSITORY.md`** - Comprehensive 600+ line guide covering everything
|
||||
- **`APT_REPO_SUMMARY.md`** - This file
|
||||
|
||||
### GitHub Actions
|
||||
- **`.github/workflows/publish-apt-repo.yml`** - Automated building, signing, and publishing
|
||||
|
||||
## 🚀 Quick Start (Choose One)
|
||||
|
||||
### Option 1: Interactive Setup (Recommended for First Time)
|
||||
|
||||
Run the setup wizard:
|
||||
|
||||
```bash
|
||||
./scripts/setup-apt-repo.sh
|
||||
```
|
||||
|
||||
This walks you through:
|
||||
1. ✅ Checking prerequisites
|
||||
2. 🔑 Setting up GPG key
|
||||
3. 📦 Finding/building packages
|
||||
4. 📝 Creating repository structure
|
||||
5. ✍️ Signing the repository
|
||||
6. 📋 Next steps to publish to gh-pages
|
||||
|
||||
### Option 2: Manual Step-by-Step
|
||||
|
||||
```bash
|
||||
# 1. Initialize
|
||||
./scripts/init-apt-repo.sh
|
||||
|
||||
# 2. Build packages
|
||||
cargo deb --package socktop
|
||||
cargo deb --package socktop_agent
|
||||
|
||||
# 3. Add packages
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop_*.deb
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop-agent_*.deb
|
||||
|
||||
# 4. Sign (replace YOUR-KEY-ID)
|
||||
./scripts/sign-apt-repo.sh apt-repo stable YOUR-KEY-ID
|
||||
|
||||
# 5. Update URLs
|
||||
sed -i 's/YOUR-USERNAME/your-github-username/g' apt-repo/*.{md,html}
|
||||
|
||||
# 6. Publish to gh-pages (see below)
|
||||
```
|
||||
|
||||
### Option 3: Fully Automated (After Initial Setup)
|
||||
|
||||
Once gh-pages branch exists, just tag releases:
|
||||
|
||||
```bash
|
||||
git tag v1.50.0
|
||||
git push --tags
|
||||
|
||||
# GitHub Actions will:
|
||||
# - Build packages for AMD64 and ARM64
|
||||
# - Update APT repository
|
||||
# - Sign with your GPG key
|
||||
# - Push to gh-pages branch automatically
|
||||
```
|
||||
|
||||
## 📤 Publishing to GitHub Pages (gh-pages branch)
|
||||
|
||||
**Why gh-pages branch?**
|
||||
- ✅ Keeps main branch clean (source code only)
|
||||
- ✅ Separate branch for published content
|
||||
- ✅ GitHub Actions can auto-update it
|
||||
- ✅ You can customize the landing page
|
||||
|
||||
**Initial Setup:**
|
||||
```bash
|
||||
# Create gh-pages branch
|
||||
git checkout --orphan gh-pages
|
||||
git rm -rf .
|
||||
|
||||
# Copy apt-repo CONTENTS to root (not the folder!)
|
||||
cp -r apt-repo/* .
|
||||
rm -rf apt-repo
|
||||
|
||||
# Commit and push
|
||||
git add .
|
||||
git commit -m "Initialize APT repository"
|
||||
git push -u origin gh-pages
|
||||
|
||||
# Return to main
|
||||
git checkout main
|
||||
```
|
||||
|
||||
**Enable in GitHub:**
|
||||
1. Settings → Pages
|
||||
2. Source: **gh-pages** → **/ (root)**
|
||||
3. Save
|
||||
|
||||
Your repo will be at: `https://your-username.github.io/socktop/`
|
||||
|
||||
**Note:** GitHub Pages only allows `/` (root) or `/docs`. Since we use gh-pages branch, contents go in the root of that branch.
|
||||
|
||||
See `SETUP_GITHUB_PAGES.md` for detailed step-by-step instructions.
|
||||
|
||||
### Alternative: Self-Hosted Server
|
||||
|
||||
Copy `apt-repo/` contents to your web server:
|
||||
```bash
|
||||
rsync -avz apt-repo/ user@example.com:/var/www/apt/
|
||||
```
|
||||
|
||||
Configure Apache/Nginx to serve the directory. See `docs/APT_REPOSITORY.md` for details.
|
||||
|
||||
## 🤖 GitHub Actions Automation
|
||||
|
||||
### Required Secrets
|
||||
|
||||
Add these in GitHub Settings → Secrets → Actions:
|
||||
|
||||
1. **GPG_PRIVATE_KEY**
|
||||
```bash
|
||||
gpg --armor --export-secret-key YOUR-KEY-ID
|
||||
# Copy entire output including BEGIN/END lines
|
||||
```
|
||||
|
||||
2. **GPG_KEY_ID**
|
||||
```bash
|
||||
gpg --list-secret-keys --keyid-format LONG
|
||||
# Use the ID after "rsa4096/"
|
||||
```
|
||||
|
||||
3. **GPG_PASSPHRASE**
|
||||
```bash
|
||||
# Your GPG passphrase (leave empty if no passphrase)
|
||||
```
|
||||
|
||||
### Triggers
|
||||
|
||||
The workflow runs on:
|
||||
- **Version tags**: `git tag v1.50.0 && git push --tags`
|
||||
- **Manual dispatch**: Actions tab → "Publish APT Repository" → Run workflow
|
||||
|
||||
### What It Does
|
||||
|
||||
1. ✅ Builds packages for AMD64 and ARM64
|
||||
2. ✅ Initializes or updates APT repository
|
||||
3. ✅ Generates Packages files and metadata
|
||||
4. ✅ Signs with your GPG key
|
||||
5. ✅ Commits and pushes to gh-pages branch
|
||||
6. ✅ Creates GitHub Release with artifacts
|
||||
7. ✅ Generates summary with installation instructions
|
||||
|
||||
## 👥 User Installation
|
||||
|
||||
Once published, users install with:
|
||||
|
||||
```bash
|
||||
# Add repository
|
||||
curl -fsSL https://your-username.github.io/socktop/KEY.gpg | \
|
||||
sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg
|
||||
|
||||
echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://your-username.github.io/socktop stable main" | \
|
||||
sudo tee /etc/apt/sources.list.d/socktop.list
|
||||
|
||||
# Install
|
||||
sudo apt update
|
||||
sudo apt install socktop socktop-agent
|
||||
|
||||
# The agent service is automatically installed and configured
|
||||
sudo systemctl enable --now socktop-agent
|
||||
```
|
||||
|
||||
## 🔧 Maintenance
|
||||
|
||||
### Release New Version (Automated)
|
||||
|
||||
```bash
|
||||
# Update version in Cargo.toml, commit changes
|
||||
git add . && git commit -m "Bump version to 1.51.0"
|
||||
git tag v1.51.0
|
||||
git push origin main --tags
|
||||
|
||||
# GitHub Actions automatically:
|
||||
# - Builds packages for AMD64 and ARM64
|
||||
# - Updates apt-repo
|
||||
# - Signs with GPG
|
||||
# - Pushes to gh-pages branch
|
||||
```
|
||||
|
||||
### Manual Update (if needed)
|
||||
|
||||
```bash
|
||||
# On main branch
|
||||
cargo deb --package socktop
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop_*.deb
|
||||
./scripts/sign-apt-repo.sh
|
||||
|
||||
# Switch to gh-pages and update
|
||||
git checkout gh-pages
|
||||
cp -r apt-repo/* .
|
||||
git add . && git commit -m "Release v1.51.0" && git push
|
||||
git checkout main
|
||||
```
|
||||
|
||||
### Remove Old Versions
|
||||
|
||||
```bash
|
||||
# On gh-pages branch
|
||||
git checkout gh-pages
|
||||
rm pool/main/socktop_1.50.0_*.deb
|
||||
# Regenerate metadata (re-add remaining packages)
|
||||
git add . && git commit -m "Remove old versions" && git push
|
||||
git checkout main
|
||||
```
|
||||
|
||||
## 🎯 Key Benefits
|
||||
|
||||
✅ **No sponsor needed** - Host your own repository
|
||||
✅ **Full control** - You decide when to release
|
||||
✅ **Free hosting** - GitHub Pages at no cost
|
||||
✅ **Automated** - GitHub Actions does the work
|
||||
✅ **Professional** - Just like official repos
|
||||
✅ **Multi-arch** - AMD64, ARM64 support built-in
|
||||
✅ **Secure** - GPG signed packages
|
||||
✅ **Easy updates** - Users get updates via `apt upgrade`
|
||||
|
||||
## 📊 Repository Structure
|
||||
|
||||
```
|
||||
apt-repo/
|
||||
├── dists/
|
||||
│ └── stable/
|
||||
│ ├── Release # Main metadata (checksums)
|
||||
│ ├── Release.gpg # Detached signature
|
||||
│ ├── InRelease # Clearsigned release
|
||||
│ └── main/
|
||||
│ ├── binary-amd64/
|
||||
│ │ ├── Packages # Package list
|
||||
│ │ ├── Packages.gz # Compressed
|
||||
│ │ └── Release # Component metadata
|
||||
│ ├── binary-arm64/
|
||||
│ └── binary-armhf/
|
||||
├── pool/
|
||||
│ └── main/
|
||||
│ ├── socktop_1.50.0_amd64.deb
|
||||
│ ├── socktop-agent_1.50.1_amd64.deb
|
||||
│ ├── socktop_1.50.0_arm64.deb
|
||||
│ └── socktop-agent_1.50.1_arm64.deb
|
||||
├── KEY.gpg # Public GPG key
|
||||
├── README.md # Repository info
|
||||
├── index.html # Web interface
|
||||
└── packages.html # Package listing
|
||||
```
|
||||
|
||||
## 🔑 GPG Key Management
|
||||
|
||||
### Create New Key
|
||||
|
||||
```bash
|
||||
gpg --full-generate-key
|
||||
# Choose RSA 4096, no expiration (or 2 years)
|
||||
```
|
||||
|
||||
### Export Keys
|
||||
|
||||
```bash
|
||||
# Public key (for users)
|
||||
gpg --armor --export YOUR-KEY-ID > KEY.gpg
|
||||
|
||||
# Private key (for GitHub Secrets)
|
||||
gpg --armor --export-secret-key YOUR-KEY-ID
|
||||
```
|
||||
|
||||
### Backup Keys
|
||||
|
||||
```bash
|
||||
# Backup to safe location
|
||||
gpg --export-secret-keys YOUR-KEY-ID > gpg-private-backup.key
|
||||
gpg --export YOUR-KEY-ID > gpg-public-backup.key
|
||||
```
|
||||
|
||||
### Key Rotation
|
||||
|
||||
If your key expires or is compromised:
|
||||
```bash
|
||||
./scripts/sign-apt-repo.sh apt-repo stable NEW-KEY-ID
|
||||
gpg --armor --export NEW-KEY-ID > apt-repo/KEY.gpg
|
||||
# Users need to re-import the key
|
||||
```
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### "Repository not signed"
|
||||
```bash
|
||||
./scripts/sign-apt-repo.sh apt-repo stable YOUR-KEY-ID
|
||||
ls apt-repo/dists/stable/Release* # Should show 3 files
|
||||
```
|
||||
|
||||
### "Package not found"
|
||||
```bash
|
||||
cd apt-repo
|
||||
dpkg-scanpackages --arch amd64 pool/main /dev/null > dists/stable/main/binary-amd64/Packages
|
||||
gzip -9 -k -f dists/stable/main/binary-amd64/Packages
|
||||
cd ..
|
||||
./scripts/sign-apt-repo.sh
|
||||
```
|
||||
|
||||
### "404 Not Found" on GitHub Pages
|
||||
- Wait 2-3 minutes after pushing
|
||||
- Check Settings → Pages is enabled
|
||||
- Verify source branch/directory
|
||||
|
||||
### GitHub Actions not signing
|
||||
- Check all 3 secrets are set correctly
|
||||
- GPG_PRIVATE_KEY must include BEGIN/END lines
|
||||
- Test signing locally first
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
| File | Purpose | Length |
|
||||
|------|---------|--------|
|
||||
| `QUICK_START_APT_REPO.md` | Get started in < 10 minutes | Quick |
|
||||
| `SETUP_GITHUB_PAGES.md` | Detailed gh-pages setup guide | Step-by-step |
|
||||
| `docs/APT_REPOSITORY.md` | Complete guide with all options | Comprehensive |
|
||||
| `docs/DEBIAN_PACKAGING.md` | How .deb packages are built | Technical |
|
||||
| `DEBIAN_PACKAGING_SUMMARY.md` | Overview of packaging work | Summary |
|
||||
| `APT_REPO_SUMMARY.md` | This file | Overview |
|
||||
|
||||
## 🎓 Learning Path
|
||||
|
||||
1. **Start here**: `QUICK_START_APT_REPO.md` (10 min)
|
||||
2. **Set up**: Run `./scripts/setup-apt-repo.sh` (15 min)
|
||||
3. **Publish**: Follow `SETUP_GITHUB_PAGES.md` (5 min)
|
||||
4. **Automate**: Set up GitHub Actions secrets (10 min)
|
||||
5. **Advanced**: Read `docs/APT_REPOSITORY.md` as needed
|
||||
|
||||
## 🚦 Next Steps
|
||||
|
||||
Choose your path:
|
||||
|
||||
### Just Getting Started?
|
||||
1. ✅ Read `QUICK_START_APT_REPO.md`
|
||||
2. ✅ Run `./scripts/setup-apt-repo.sh`
|
||||
3. ✅ Follow `SETUP_GITHUB_PAGES.md` to publish
|
||||
4. ✅ Test installation on a VM
|
||||
|
||||
### Want Automation?
|
||||
1. ✅ Generate/export GPG key
|
||||
2. ✅ Add GitHub Secrets
|
||||
3. ✅ Tag a release: `git tag v1.50.0 && git push --tags`
|
||||
4. ✅ Watch GitHub Actions magic happen
|
||||
|
||||
### Want to Understand Everything?
|
||||
1. ✅ Read `docs/APT_REPOSITORY.md` (comprehensive)
|
||||
2. ✅ Study the scripts in `scripts/`
|
||||
3. ✅ Examine `.github/workflows/publish-apt-repo.yml`
|
||||
4. ✅ Learn about Debian repository format
|
||||
|
||||
### Ready for Production?
|
||||
1. ✅ Set up monitoring/analytics
|
||||
2. ✅ Create PPA for Ubuntu (Launchpad)
|
||||
3. ✅ Apply to Debian mentors for official inclusion
|
||||
4. ✅ Set up repository mirrors
|
||||
5. ✅ Document best practices for users
|
||||
|
||||
## 🌟 Success Criteria
|
||||
|
||||
You'll know you're successful when:
|
||||
|
||||
- [ ] Users can `apt install socktop`
|
||||
- [ ] Updates work with `apt upgrade`
|
||||
- [ ] Multiple architectures supported
|
||||
- [ ] Repository is GPG signed
|
||||
- [ ] GitHub Actions publishes automatically
|
||||
- [ ] Installation instructions in README
|
||||
- [ ] Zero sponsor or approval needed
|
||||
|
||||
## 💡 Pro Tips
|
||||
|
||||
1. **Test first**: Always test on a fresh VM before publishing
|
||||
2. **Keep versions**: Don't delete old .deb files immediately
|
||||
3. **Backup GPG key**: Store it safely offline
|
||||
4. **Monitor downloads**: Use GitHub Insights or server logs
|
||||
5. **Document everything**: Help users troubleshoot
|
||||
6. **Version consistently**: Use semantic versioning
|
||||
7. **Sign always**: Never publish unsigned repositories
|
||||
|
||||
## 🔗 Resources
|
||||
|
||||
- [Debian Repository Format](https://wiki.debian.org/DebianRepository/Format)
|
||||
- [GitHub Pages Docs](https://docs.github.com/en/pages)
|
||||
- [cargo-deb](https://github.com/kornelski/cargo-deb)
|
||||
- [Ubuntu PPA Guide](https://help.launchpad.net/Packaging/PPA)
|
||||
- [Debian Mentors](https://mentors.debian.net/)
|
||||
|
||||
## 🎊 Congratulations!
|
||||
|
||||
You now have everything you need to:
|
||||
- ✅ Create your own APT repository
|
||||
- ✅ Host it for free on GitHub Pages
|
||||
- ✅ Automate the entire process
|
||||
- ✅ Distribute packages professionally
|
||||
- ✅ Provide easy installation for users
|
||||
|
||||
**No sponsor required. No approval needed. You're in control!** 🚀
|
||||
|
||||
---
|
||||
|
||||
**Questions?** Check the docs or open an issue.
|
||||
|
||||
**Ready to publish?** Run `./scripts/setup-apt-repo.sh` and follow the wizard!
|
||||
@@ -1,43 +0,0 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"socktop",
|
||||
"socktop_agent"
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
# async + streams
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
futures-util = "0.3"
|
||||
anyhow = "1.0"
|
||||
|
||||
# websocket
|
||||
tokio-tungstenite = { version = "0.24", features = ["__rustls-tls", "connect"] }
|
||||
url = "2.5"
|
||||
|
||||
# JSON + error handling
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# system stats (align across crates)
|
||||
sysinfo = "0.37"
|
||||
|
||||
# CLI UI
|
||||
ratatui = "0.28"
|
||||
crossterm = "0.27"
|
||||
|
||||
|
||||
# web server (remote-agent)
|
||||
axum = { version = "0.7", features = ["ws"] }
|
||||
|
||||
# protobuf
|
||||
prost = "0.13"
|
||||
dirs-next = "2"
|
||||
|
||||
[profile.release]
|
||||
# Favor smaller, simpler binaries with good runtime perf
|
||||
lto = "thin"
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
opt-level = 3
|
||||
strip = "symbols"
|
||||
@@ -0,0 +1,109 @@
|
||||
# 🚀 Get Your APT Repository Live in 5 Minutes
|
||||
|
||||
## You're Here Because...
|
||||
|
||||
You want to publish socktop packages via APT, but GitHub Pages won't let you select `apt-repo/` folder. Here's why and how to fix it:
|
||||
|
||||
**The Issue:** GitHub Pages only serves from `/` (root) or `/docs`, not custom folders like `/apt-repo`.
|
||||
|
||||
**The Solution:** Use a `gh-pages` branch where `apt-repo` contents go in the root.
|
||||
|
||||
## Quick Setup (5 Steps)
|
||||
|
||||
### 1. Create apt-repo locally (if you haven't)
|
||||
|
||||
```bash
|
||||
./scripts/setup-apt-repo.sh
|
||||
```
|
||||
|
||||
This creates `apt-repo/` with your packages and signs them.
|
||||
|
||||
### 2. Create gh-pages branch
|
||||
|
||||
```bash
|
||||
git checkout --orphan gh-pages
|
||||
git rm -rf .
|
||||
```
|
||||
|
||||
### 3. Copy apt-repo to root
|
||||
|
||||
```bash
|
||||
cp -r apt-repo/* .
|
||||
rm -rf apt-repo
|
||||
ls
|
||||
# You should see: dists/ pool/ KEY.gpg index.html README.md
|
||||
```
|
||||
|
||||
### 4. Push to GitHub
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Initialize APT repository"
|
||||
git push -u origin gh-pages
|
||||
git checkout main
|
||||
```
|
||||
|
||||
### 5. Enable GitHub Pages
|
||||
|
||||
1. Go to: **Settings → Pages**
|
||||
2. Source: **gh-pages** → **/ (root)**
|
||||
3. Click **Save**
|
||||
|
||||
**Done!** ✅ Your repo will be live at `https://your-username.github.io/socktop/` in 1-2 minutes.
|
||||
|
||||
## Test It
|
||||
|
||||
```bash
|
||||
curl -I https://your-username.github.io/socktop/KEY.gpg
|
||||
# Should return: HTTP/2 200
|
||||
```
|
||||
|
||||
## Install It (On Any Debian/Ubuntu System)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://your-username.github.io/socktop/KEY.gpg | \
|
||||
sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg
|
||||
|
||||
echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://your-username.github.io/socktop stable main" | \
|
||||
sudo tee /etc/apt/sources.list.d/socktop.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install socktop socktop-agent
|
||||
```
|
||||
|
||||
## What's Next?
|
||||
|
||||
### Now (Optional):
|
||||
- Customize `index.html` on gh-pages for a nice landing page
|
||||
- Add installation instructions to your main README
|
||||
|
||||
### Later:
|
||||
- Set up GitHub Actions automation (see `QUICK_START_APT_REPO.md`)
|
||||
- Add more architectures (ARM64, ARMv7)
|
||||
|
||||
## Understanding the Setup
|
||||
|
||||
```
|
||||
main branch: gh-pages branch:
|
||||
├── src/ ├── dists/
|
||||
├── Cargo.toml ├── pool/
|
||||
├── scripts/ ├── KEY.gpg
|
||||
└── apt-repo/ (local) └── index.html ← GitHub Pages serves this
|
||||
|
||||
Work here ↑ Published here ↑
|
||||
```
|
||||
|
||||
- **main**: Your development work
|
||||
- **gh-pages**: What users see/download
|
||||
- **apt-repo/**: Local folder (ignored in git, see `.gitignore`)
|
||||
|
||||
## Need More Help?
|
||||
|
||||
- **Quick start**: `QUICK_START_APT_REPO.md`
|
||||
- **Detailed setup**: `SETUP_GITHUB_PAGES.md`
|
||||
- **Why gh-pages?**: `WHY_GHPAGES_BRANCH.md`
|
||||
- **Full guide**: `docs/APT_REPOSITORY.md`
|
||||
|
||||
---
|
||||
|
||||
**You got this!** 🎉
|
||||
@@ -0,0 +1,42 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQGNBGkih7QBDADgX6sYMx2Lp6qcZxeCCizcy4TFsxcRJfp5mfbMplVES0hQToIP
|
||||
EMC11JqPwQdLliXKjUr8Z2kgM2oqvH+dkdgzUGrw6kTK8YHc+qs37iJAOVS9D72X
|
||||
tTld282NrtFwzb74nS2GKPkpWI7aSKBpHtWFPX/1ONsc56qGqFd3wwikEvCz8MeJ
|
||||
HwCD1JZ9F+2DyyXWsTJNgDwPloJSUbtyVuk2gd6PeTg7AQdx92Pk/mggmYbHtP8N
|
||||
wy072ku1g8K/hplmwIOGpSx1JWvAQkDU/Bb/jSqrYg2wSHO7IQnYE8I3x/zglYBl
|
||||
FYNh47TVQr0zPVSYR1MQkHU5YLBTDc5UgDvtcsYUiTtq4D/m8HWmKja0/UKGxvDJ
|
||||
P5sUPcp4dk77RdoCtUe5HImYGS8lo5N3+t0lz8sd9rYmRiIO4f7FJaJqJeHbUJyn
|
||||
iw/GCQh5D5/D571dICrEq/QhL+k5KhJljPGoVMGPFXJIc7q+CxvGp2oOo5fOlbOn
|
||||
3kSrM93AJPwT8FMAEQEAAbRFSmFzb24gV2l0dHkgKHNvY2t0b3AgYXB0IHNpZ25p
|
||||
bmcga2V5KSA8amFzb25wd2l0dHkrc29ja3RvcEBwcm90b24ubWU+iQHOBBMBCgA4
|
||||
FiEEHnVWqAU5uDlLwoINESwaeYRl+/IFAmkih7QCGwMFCwkIBwIGFQoJCAsCBBYC
|
||||
AwECHgECF4AACgkQESwaeYRl+/KV+gwAzfZVZEhO7MQV2EmNeKVK1GycFSm2oUAl
|
||||
ZbwNIEHu6+tOzqXJb8o65BtGlbLSGavsMpgRCK2SL83DdLOkutG1ahQiJr+5GaXC
|
||||
zbQgX+VWqGPZtQ+I6/rVoYZPMTCrqpAmFgvVpqv0xod7w8/wny8/XmhQ37KY2/0l
|
||||
B38oNTvdA7C8jzSrI6kr3XqurvQRW7z+MnC+nCp9Ob9bYtY0kpd4U3NrVdb8m32U
|
||||
d5LVFwD1OGvzLOSqyJ33IKjSJc4KLvW+aEsHXe+fHO9UEzH8Nbo5MmVvX3QIHiyq
|
||||
jD4zN16AGsGYqCK4irtQCiD3wBOdsG/RVkgIcdlmAH3EGEp7Ux8+7v1PXYI+UrSs
|
||||
XE7f1xFTJ2r5TMex6W3he073Em4qhQsrnMF5syTZsM6N+5UqXVOM1RuDVVXr7929
|
||||
hC3G8pK/A2W5Lwpxl2yzock2CxhvUn7M/xm4VbcPlWTCUd/QzU8VtsgaGHcuhi5e
|
||||
xHY1AU07STLB9RinjBVf2bmk4oDQcmB6uQGNBGkih7QBDACrjE+xSWP92n931/5t
|
||||
+tXcujwFlIpSZdbSQFr0B0YyjPRUP4FSzEGu8vuM5ChUfWKhmN1dDr5C4qFo9NgQ
|
||||
6oCN2HubajSGyXNwnOMlMb5ck79Ubmy9yDV9/ZLqpJJiozGap2/EnNoDhaANlmUg
|
||||
rfqUHpIB8XC2IZ0Itt05tp/u78dJiB+R6ReZn/bVUafNV4jIqYZfLRzI3FTJ4xvK
|
||||
FGs/ER+JajAdJQ8LPfazmDQSGw0huguxhopZwKQ/qWZMn1OHq/ZaPvCqbQt3irLw
|
||||
dLPDC4pEaYGRyADYeyuarG0DVyUQ9XRc/NufKDvOAn33LpBPBpcvNQAsVhWTCYl7
|
||||
ogQ+suVYVN8Tu7v4bUSHKwzXKvLN/ojJX/Fh7eTW4TPsgLHNHAEDUkSQozIe9vO6
|
||||
o+vydDqRxuXJgdkR7lqP6PQDYrhRYZGJf57eKf6VtTKYFaMbiMWPU+vcHeB0/iDe
|
||||
Pv81qro2LD2PG5WCzDpNETBceCTjykb9r0VHx4/JsiojKmsAEQEAAYkBtgQYAQoA
|
||||
IBYhBB51VqgFObg5S8KCDREsGnmEZfvyBQJpIoe0AhsMAAoJEBEsGnmEZfvyNp8M
|
||||
AIH+6+hGB3qADdnhNgb+3fN0511eK9Uk82lxgGARLcD8GN1UP0HlvEqkxCHy3PUe
|
||||
tHcsuYVz7i8pmpEGdFx9zv7MelenUsJniUQ++OZKx6iUG/MYqz//NxY+5lyRmcu2
|
||||
aYvUxhkgf9zgxXTkTyV2VV32mX//cHcwc+c/089QAPzCMaSrHdNK+ED9+k8uquJ1
|
||||
lSL9Bm15z/EV42v9Q/4KTM5OBLHpNw0Rvn9C0iuZVwHXBrrA/HSGXpA54AqNUMpZ
|
||||
kRPgLQcy5yVE2y1aXLXt2XdTn6YPzrAjNoazYYuCWHYIZU7dGkIswpsDirDLKHdD
|
||||
onb3VShmSpemYjsuFiqhfi6qwCkeHsz/CpQAp70SZ+z9oB8H80PJVKPbPIP3zEf3
|
||||
i7bcsqHA7stF+8sJclXgxBUBeDJ3O2jN/scBOcvNA6xoRp7+oJbnjDRuxBmh+fVg
|
||||
TIuw2++vTF2Ml0EMv7ePTpr7b1DofuJRNYGkuAIMVXHjLTqMiTJUce3OUy003zMg
|
||||
Dg==
|
||||
=AaPQ
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
@@ -0,0 +1,221 @@
|
||||
# Quick Start: Setting Up Your socktop APT Repository
|
||||
|
||||
This guide will get your APT repository up and running in **under 10 minutes**.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [ ] Debian packages built (or use GitHub Actions to build them)
|
||||
- [ ] GPG key for signing
|
||||
- [ ] GitHub repository with Pages enabled
|
||||
|
||||
## Step 1: Create GPG Key (if needed)
|
||||
|
||||
```bash
|
||||
# Generate a new key
|
||||
gpg --full-generate-key
|
||||
|
||||
# Select:
|
||||
# - RSA and RSA (default)
|
||||
# - 4096 bits
|
||||
# - Key does not expire (or 2 years)
|
||||
# - Your name and email
|
||||
|
||||
# Get your key ID
|
||||
gpg --list-secret-keys --keyid-format LONG
|
||||
# Look for the part after "rsa4096/" - that's your KEY-ID
|
||||
```
|
||||
|
||||
## Step 2: Initialize Repository Locally
|
||||
|
||||
```bash
|
||||
cd socktop
|
||||
|
||||
# Create the repository structure
|
||||
./scripts/init-apt-repo.sh
|
||||
|
||||
# Build packages (or download from GitHub Actions)
|
||||
cargo install cargo-deb
|
||||
cargo deb --package socktop
|
||||
cargo deb --package socktop_agent
|
||||
|
||||
# Add packages to repository
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop_*.deb
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop-agent_*.deb
|
||||
|
||||
# Sign the repository (replace YOUR-KEY-ID with actual key ID)
|
||||
./scripts/sign-apt-repo.sh apt-repo stable YOUR-KEY-ID
|
||||
|
||||
# Update URLs with your GitHub username
|
||||
sed -i 's/YOUR-USERNAME/your-github-username/g' apt-repo/README.md apt-repo/index.html
|
||||
```
|
||||
|
||||
## Step 3: Publish to GitHub Pages (gh-pages branch)
|
||||
|
||||
```bash
|
||||
# Create gh-pages branch
|
||||
git checkout --orphan gh-pages
|
||||
git rm -rf .
|
||||
|
||||
# Copy apt-repo CONTENTS to root (not the folder itself)
|
||||
cp -r apt-repo/* .
|
||||
rm -rf apt-repo
|
||||
|
||||
# Commit and push
|
||||
git add .
|
||||
git commit -m "Initialize APT repository"
|
||||
git push -u origin gh-pages
|
||||
|
||||
# Go back to main branch
|
||||
git checkout main
|
||||
```
|
||||
|
||||
Then in GitHub:
|
||||
1. Go to **Settings → Pages**
|
||||
2. Source: **Deploy from a branch**
|
||||
3. Branch: **gh-pages** → **/ (root)** → **Save**
|
||||
|
||||
Wait 1-2 minutes, then visit: `https://your-username.github.io/socktop/`
|
||||
|
||||
## Step 4: Automate with GitHub Actions
|
||||
|
||||
Add these secrets to your repository (Settings → Secrets → Actions):
|
||||
|
||||
```bash
|
||||
# Export your private key
|
||||
gpg --armor --export-secret-key YOUR-KEY-ID
|
||||
|
||||
# Copy the ENTIRE output and save as secret: GPG_PRIVATE_KEY
|
||||
```
|
||||
|
||||
Add these three secrets:
|
||||
- **GPG_PRIVATE_KEY**: Your exported private key
|
||||
- **GPG_KEY_ID**: Your key ID (e.g., `ABC123DEF456`)
|
||||
- **GPG_PASSPHRASE**: Your key passphrase (leave empty if no passphrase)
|
||||
|
||||
The workflow in `.github/workflows/publish-apt-repo.yml` will now:
|
||||
- Build packages for AMD64 and ARM64
|
||||
- Update the APT repository
|
||||
- Sign with your GPG key
|
||||
- Push to gh-pages automatically
|
||||
|
||||
Trigger it by:
|
||||
- Creating a version tag: `git tag v1.50.0 && git push --tags`
|
||||
- Manual dispatch from GitHub Actions tab
|
||||
|
||||
## Step 5: Test It
|
||||
|
||||
On any Debian/Ubuntu system:
|
||||
|
||||
```bash
|
||||
# Add your repository
|
||||
curl -fsSL https://your-username.github.io/socktop/KEY.gpg | \
|
||||
sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg
|
||||
|
||||
echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://your-username.github.io/socktop stable main" | \
|
||||
sudo tee /etc/apt/sources.list.d/socktop.list
|
||||
|
||||
# Install
|
||||
sudo apt update
|
||||
sudo apt install socktop socktop-agent
|
||||
|
||||
# Verify
|
||||
socktop --version
|
||||
socktop_agent --version
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Add a New Version
|
||||
|
||||
```bash
|
||||
# Build new packages
|
||||
cargo deb --package socktop
|
||||
cargo deb --package socktop_agent
|
||||
|
||||
# Add to repository
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop_*.deb
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop-agent_*.deb
|
||||
|
||||
# Re-sign
|
||||
./scripts/sign-apt-repo.sh apt-repo stable YOUR-KEY-ID
|
||||
|
||||
# Publish
|
||||
cd docs/apt # or wherever your apt-repo is
|
||||
git add .
|
||||
git commit -m "Release v1.51.0"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### Or Just Tag and Let GitHub Actions Do It
|
||||
|
||||
```bash
|
||||
# Update version in Cargo.toml
|
||||
# Commit changes
|
||||
git add .
|
||||
git commit -m "Bump version to 1.51.0"
|
||||
|
||||
# Tag and push
|
||||
git tag v1.51.0
|
||||
git push origin main --tags
|
||||
|
||||
# GitHub Actions will:
|
||||
# - Build packages for AMD64 and ARM64
|
||||
# - Update gh-pages branch automatically
|
||||
# - Sign and publish!
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Repository not signed" error
|
||||
|
||||
Make sure you signed it:
|
||||
```bash
|
||||
./scripts/sign-apt-repo.sh apt-repo stable YOUR-KEY-ID
|
||||
ls apt-repo/dists/stable/Release*
|
||||
# Should show: Release, Release.gpg, InRelease, KEY.gpg
|
||||
```
|
||||
|
||||
### "404 Not Found" on GitHub Pages
|
||||
|
||||
1. Check Settings → Pages is enabled
|
||||
2. Wait 2-3 minutes for GitHub to deploy
|
||||
3. Verify the URL structure matches your settings
|
||||
|
||||
### GitHub Actions not signing
|
||||
|
||||
Check that all three secrets are set correctly:
|
||||
- Settings → Secrets and variables → Actions
|
||||
- Make sure GPG_PRIVATE_KEY includes the BEGIN/END lines
|
||||
- Test locally first
|
||||
|
||||
## What's Next?
|
||||
|
||||
✅ You now have a working APT repository!
|
||||
|
||||
**Share it:**
|
||||
- Add installation instructions to your main README
|
||||
- Tweet/blog about it
|
||||
- Submit to awesome-rust lists
|
||||
|
||||
**Improve it:**
|
||||
- Customize your GitHub Pages site (it's just HTML!)
|
||||
- Add more architectures (ARMv7)
|
||||
- Create multiple distributions (stable, testing)
|
||||
- Set up download statistics
|
||||
- Apply to Ubuntu PPA (Launchpad)
|
||||
- Eventually submit to official Debian repos
|
||||
|
||||
## Full Documentation
|
||||
|
||||
For detailed information, see:
|
||||
- `docs/APT_REPOSITORY.md` - Complete APT repository guide
|
||||
- `docs/DEBIAN_PACKAGING.md` - Debian packaging details
|
||||
- `DEBIAN_PACKAGING_SUMMARY.md` - Quick summary
|
||||
|
||||
## Questions?
|
||||
|
||||
Open an issue on GitHub or check the full documentation.
|
||||
|
||||
---
|
||||
|
||||
**Happy packaging! 📦**
|
||||
@@ -1,545 +1,38 @@
|
||||
# socktop
|
||||
# socktop APT Repository
|
||||
|
||||
socktop is a remote system monitor with a rich TUI, inspired by top/btop, talking to a lightweight agent over WebSockets.
|
||||
This repository contains Debian packages for socktop and socktop-agent.
|
||||
|
||||
- Linux agent: near-zero CPU when idle (request-driven, no always-on sampler)
|
||||
- TUI: smooth graphs, sortable process table, scrollbars, readable colors
|
||||
## Adding this repository
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- Remote monitoring via WebSocket (JSON over WS)
|
||||
- Optional WSS (TLS): agent auto‑generates a self‑signed cert on first run; client pins the cert via --tls-ca/-t
|
||||
- TUI built with ratatui
|
||||
- CPU
|
||||
- Overall sparkline + per-core mini bars
|
||||
- Accurate per-process CPU% (Linux /proc deltas), normalized to 0–100%
|
||||
- Memory/Swap gauges with human units
|
||||
- Disks: per-device usage
|
||||
- Network: per-interface throughput with sparklines and peak markers
|
||||
- Temperatures: CPU (optional)
|
||||
- Top processes (top 50)
|
||||
- PID, name, CPU%, memory, and memory%
|
||||
- Click-to-sort by CPU% or Mem (descending)
|
||||
- Scrollbar and mouse/keyboard scrolling
|
||||
- Total process count shown in the header
|
||||
- Only top-level processes listed (threads hidden) — matches btop/top
|
||||
- Optional GPU metrics (can be disabled)
|
||||
- Optional auth token for the agent
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites: Install Rust (rustup)
|
||||
|
||||
Rust is fast, safe, and cross‑platform. Installing it will make your machine better. Consider yourself privileged.
|
||||
|
||||
Linux/macOS:
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
# load cargo for this shell
|
||||
source "$HOME/.cargo/env"
|
||||
# ensure stable is up to date
|
||||
rustup update stable
|
||||
rustc --version
|
||||
cargo --version
|
||||
# after install you may need to reload your shell, e.g.:
|
||||
exec bash # or: exec zsh / exec fish
|
||||
```
|
||||
|
||||
Windows (for the brave): install from https://rustup.rs with the MSVC toolchain. Yes, you’ll need Visual Studio Build Tools. You chose Windows — enjoy the ride.
|
||||
|
||||
### Raspberry Pi / Ubuntu / PopOS (required)
|
||||
|
||||
Install GPU support with apt command below
|
||||
Add the repository to your system:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install libdrm-dev libdrm-amdgpu1
|
||||
# Add the GPG key
|
||||
curl -fsSL https://jasonwitty.github.io/socktop/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg
|
||||
|
||||
# Add the repository
|
||||
echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://jasonwitty.github.io/socktop stable main" | sudo tee /etc/apt/sources.list.d/socktop.list
|
||||
|
||||
# Update and install
|
||||
sudo apt update
|
||||
sudo apt install socktop socktop-agent
|
||||
```
|
||||
|
||||
---
|
||||
## Manual Installation
|
||||
|
||||
## Architecture
|
||||
|
||||
Two components:
|
||||
|
||||
1) Agent (remote): small Rust WS server using sysinfo + /proc. It collects metrics only when the client requests them over the WebSocket (request-driven). No background sampling loop.
|
||||
|
||||
2) Client (local): TUI that connects to ws://HOST:PORT/ws (or wss://HOST:PORT/ws when TLS is enabled) and renders updates.
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
- Build both binaries:
|
||||
You can also download and install packages manually from the `pool/main/` directory.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/jasonwitty/socktop.git
|
||||
cd socktop
|
||||
cargo build --release
|
||||
wget https://jasonwitty.github.io/socktop/pool/main/socktop_VERSION_ARCH.deb
|
||||
sudo dpkg -i socktop_VERSION_ARCH.deb
|
||||
```
|
||||
|
||||
- Start the agent on the target machine (default port 3000):
|
||||
## Supported Architectures
|
||||
|
||||
```bash
|
||||
./target/release/socktop_agent --port 3000
|
||||
```
|
||||
- amd64 (x86_64)
|
||||
- arm64 (aarch64)
|
||||
- armhf (32-bit ARM)
|
||||
|
||||
- Connect with the TUI from your local machine:
|
||||
## Building from Source
|
||||
|
||||
```bash
|
||||
./target/release/socktop ws://REMOTE_HOST:3000/ws
|
||||
```
|
||||
|
||||
### Quick demo (no agent setup)
|
||||
|
||||
Spin up a temporary local agent on port 3231 and connect automatically:
|
||||
|
||||
```bash
|
||||
socktop --demo
|
||||
```
|
||||
|
||||
Or just run `socktop` with no arguments and pick the built‑in `demo` entry from the interactive profile list (if you have saved profiles, `demo` is appended). The demo agent:
|
||||
|
||||
- Runs locally (`ws://127.0.0.1:3231/ws`)
|
||||
- Stops automatically (you'll see "Stopped demo agent on port 3231") when you quit the TUI or press Ctrl-C
|
||||
|
||||
---
|
||||
|
||||
## Install (from crates.io)
|
||||
|
||||
You don’t need to clone this repo to use socktop. Install the published binaries with cargo:
|
||||
|
||||
```bash
|
||||
# TUI (client)
|
||||
cargo install socktop
|
||||
# Agent (server)
|
||||
cargo install socktop_agent
|
||||
```
|
||||
|
||||
This drops socktop and socktop_agent into ~/.cargo/bin (add it to PATH).
|
||||
|
||||
Notes:
|
||||
- After installing Rust via rustup, reload your shell (e.g., exec bash) so cargo is on PATH.
|
||||
- Windows: you can also grab prebuilt EXEs from GitHub Actions artifacts if rustup scares you. It shouldn’t. Be brave.
|
||||
|
||||
System-wide agent (Linux)
|
||||
|
||||
```bash
|
||||
# If you installed with cargo, binaries are in ~/.cargo/bin
|
||||
sudo install -o root -g root -m 0755 "$HOME/.cargo/bin/socktop_agent" /usr/local/bin/socktop_agent
|
||||
|
||||
# Install and enable the systemd service (example unit in docs/)
|
||||
sudo install -o root -g root -m 0644 docs/socktop-agent.service /etc/systemd/system/socktop-agent.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now socktop-agent
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
# Enable SSL
|
||||
|
||||
# Stop service
|
||||
sudo systemctl stop socktop-agent
|
||||
|
||||
# Edit service to append SSL option and port
|
||||
sudo micro /etc/systemd/system/socktop-agent.service
|
||||
|
||||
--
|
||||
ExecStart=/usr/local/bin/socktop_agent --enableSSL --port 8443
|
||||
--
|
||||
|
||||
# Reload
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
# Restart
|
||||
sudo systemctl start socktop-agent
|
||||
|
||||
# check logs for certificate location
|
||||
sudo journalctl -u socktop-agent -f
|
||||
|
||||
--
|
||||
Aug 22 22:25:26 rpi-master socktop_agent[2913998]: socktop_agent: generated self-signed TLS certificate at /var/lib/socktop/.config/socktop_agent/tls/cert.pem
|
||||
--
|
||||
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
Agent (server):
|
||||
|
||||
```bash
|
||||
socktop_agent --port 3000
|
||||
# or env: SOCKTOP_PORT=3000 socktop_agent
|
||||
# optional auth: SOCKTOP_TOKEN=changeme socktop_agent
|
||||
# enable TLS (self‑signed cert, default port 8443; you can also use -p):
|
||||
socktop_agent --enableSSL --port 8443
|
||||
```
|
||||
|
||||
Client (TUI):
|
||||
|
||||
```bash
|
||||
socktop ws://HOST:3000/ws
|
||||
# with token:
|
||||
socktop "ws://HOST:3000/ws?token=changeme"
|
||||
# TLS with pinned server certificate (recommended over the internet):
|
||||
socktop --tls-ca /path/to/cert.pem wss://HOST:8443/ws
|
||||
# (By default hostname/SAN verification is skipped for ease on home networks. To enforce it add --verify-hostname)
|
||||
socktop --verify-hostname --tls-ca /path/to/cert.pem wss://HOST:8443/ws
|
||||
# shorthand:
|
||||
socktop -t /path/to/cert.pem wss://HOST:8443/ws
|
||||
# Note: providing --tls-ca/-t automatically upgrades ws:// to wss:// if you forget
|
||||
```
|
||||
|
||||
Intervals (client-driven):
|
||||
- Fast metrics: ~500 ms
|
||||
- Processes: ~2 s (top 50)
|
||||
- Disks: ~5 s
|
||||
|
||||
The agent stays idle unless queried. When queried, it collects just what’s needed.
|
||||
|
||||
---
|
||||
|
||||
## Connection Profiles (Named)
|
||||
|
||||
You can save frequently used connection settings (URL + optional TLS CA path) under a short name and reuse them later.
|
||||
|
||||
Config file location:
|
||||
|
||||
- Linux (XDG): `$XDG_CONFIG_HOME/socktop/profiles.json`
|
||||
- Fallback (when XDG not set): `~/.config/socktop/profiles.json`
|
||||
|
||||
### Creating a profile
|
||||
|
||||
First time you specify a new `--profile/-P` name together with a URL (and optional `--tls-ca`), it is saved automatically:
|
||||
|
||||
```bash
|
||||
socktop --profile prod ws://prod-host:3000/ws
|
||||
# With TLS pinning:
|
||||
socktop --profile prod-tls --tls-ca /path/to/cert.pem wss://prod-host:8443/ws
|
||||
|
||||
You can also set custom intervals (milliseconds):
|
||||
|
||||
```bash
|
||||
socktop --profile prod --metrics-interval-ms 750 --processes-interval-ms 3000 ws://prod-host:3000/ws
|
||||
```
|
||||
```
|
||||
|
||||
If a profile already exists you will be prompted before overwriting:
|
||||
|
||||
```
|
||||
$ socktop --profile prod ws://new-host:3000/ws
|
||||
Overwrite existing profile 'prod'? [y/N]: y
|
||||
```
|
||||
|
||||
To overwrite without an interactive prompt pass `--save`:
|
||||
|
||||
```bash
|
||||
socktop --profile prod --save ws://new-host:3000/ws
|
||||
```
|
||||
|
||||
### Using a saved profile
|
||||
|
||||
Just pass the profile name (no URL needed):
|
||||
|
||||
```bash
|
||||
socktop --profile prod
|
||||
socktop -P prod-tls # short flag
|
||||
```
|
||||
|
||||
The stored URL (and TLS CA path, if any) plus any saved intervals will be used. TLS auto-upgrade still applies if a CA path is stored alongside a ws:// URL.
|
||||
|
||||
### Interactive selection (no args)
|
||||
|
||||
If you run `socktop` with no arguments and at least one profile exists, you will be shown a numbered list to pick from:
|
||||
|
||||
```
|
||||
$ socktop
|
||||
Select profile:
|
||||
1. prod
|
||||
2. prod-tls
|
||||
Enter number (or blank to abort): 2
|
||||
```
|
||||
|
||||
Choosing a number starts the TUI with that profile. A built‑in `demo` option is always appended; selecting it launches a local agent on port 3231 (no TLS) and connects to `ws://127.0.0.1:3231/ws`. Pressing Enter on blank aborts without connecting.
|
||||
|
||||
### JSON format
|
||||
|
||||
An example `profiles.json` (pretty‑printed):
|
||||
|
||||
```json
|
||||
{
|
||||
"profiles": {
|
||||
"prod": { "url": "ws://prod-host:3000/ws" },
|
||||
"prod-tls": {
|
||||
"url": "wss://prod-host:8443/ws",
|
||||
"tls_ca": "/home/user/certs/prod-cert.pem",
|
||||
"metrics_interval_ms": 500,
|
||||
"processes_interval_ms": 2000
|
||||
}
|
||||
},
|
||||
"version": 0
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- The `tls_ca` path is stored as given; if you move or rotate the certificate update the profile by re-running with `--profile NAME --save`.
|
||||
- Deleting a profile: edit the JSON file and remove the entry (TUI does not yet have an in-app delete command).
|
||||
- Profiles are client-side convenience only; they do not affect the agent.
|
||||
- Intervals: `metrics_interval_ms` controls the fast metrics poll (default 500 ms). `processes_interval_ms` controls process list polling (default 2000 ms). Values below 100 ms (metrics) or 200 ms (processes) are clamped.
|
||||
|
||||
---
|
||||
|
||||
## Updating
|
||||
|
||||
Update the agent (systemd):
|
||||
|
||||
```bash
|
||||
# on the server running the agent
|
||||
cargo install socktop_agent --force
|
||||
sudo systemctl stop socktop-agent
|
||||
sudo install -o root -g root -m 0755 "$HOME/.cargo/bin/socktop_agent" /usr/local/bin/socktop_agent
|
||||
# if you changed the unit file:
|
||||
# sudo install -o root -g root -m 0644 docs/socktop-agent.service /etc/systemd/system/socktop-agent.service
|
||||
# sudo systemctl daemon-reload
|
||||
sudo systemctl start socktop-agent
|
||||
sudo systemctl status socktop-agent --no-pager
|
||||
# logs:
|
||||
# journalctl -u socktop-agent -f
|
||||
```
|
||||
|
||||
Update the TUI (client):
|
||||
```bash
|
||||
cargo install socktop --force
|
||||
socktop ws://HOST:3000/ws
|
||||
```
|
||||
|
||||
Tip: If only the binary changed, restart is enough. If the unit file changed, run sudo systemctl daemon-reload.
|
||||
|
||||
---
|
||||
|
||||
## Configuration (agent)
|
||||
|
||||
- Port:
|
||||
- Flag: --port 8080 or -p 8080
|
||||
- Positional: socktop_agent 8080
|
||||
- Env: SOCKTOP_PORT=8080
|
||||
- TLS (self‑signed):
|
||||
- Enable: --enableSSL
|
||||
- Default TLS port: 8443 (override with --port/-p)
|
||||
- Certificate/Key location (created on first TLS run):
|
||||
- Linux (XDG): $XDG_CONFIG_HOME/socktop_agent/tls/{cert.pem,key.pem} (defaults to ~/.config)
|
||||
- The agent prints these paths on creation.
|
||||
- You can set XDG_CONFIG_HOME before first run to control where certs are written.
|
||||
- Additional SANs: set `SOCKTOP_AGENT_EXTRA_SANS` (comma‑separated) before first TLS start to include extra IPs/DNS names in the cert. Example:
|
||||
```bash
|
||||
SOCKTOP_AGENT_EXTRA_SANS="192.168.1.101,myhost.internal" socktop_agent --enableSSL
|
||||
```
|
||||
This prevents client errors like `NotValidForName` when connecting via an IP not present in the default cert SAN list.
|
||||
- Expiry / rotation: the generated cert is valid for ~397 days from creation. If the agent fails to start with an "ExpiredCertificate" error (or your client reports expiry), simply delete the existing cert and key:
|
||||
```bash
|
||||
rm ~/.config/socktop_agent/tls/cert.pem ~/.config/socktop_agent/tls/key.pem
|
||||
# (adjust path if XDG_CONFIG_HOME is set or different user)
|
||||
systemctl restart socktop-agent # if running under systemd
|
||||
```
|
||||
On next TLS start the agent will generate a fresh pair. Only distribute the new cert.pem to clients (never the key).
|
||||
- Auth token (optional): SOCKTOP_TOKEN=changeme
|
||||
- Disable GPU metrics: SOCKTOP_AGENT_GPU=0
|
||||
- Disable CPU temperature: SOCKTOP_AGENT_TEMP=0
|
||||
|
||||
---
|
||||
|
||||
## Keyboard & Mouse
|
||||
|
||||
- Quit: q or Esc
|
||||
- Processes pane:
|
||||
- Click “CPU %” to sort by CPU descending
|
||||
- Click “Mem” to sort by memory descending
|
||||
- Mouse wheel: scroll
|
||||
- Drag scrollbar: scroll
|
||||
- Arrow/PageUp/PageDown/Home/End: scroll
|
||||
|
||||
---
|
||||
|
||||
## Example agent JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"cpu_total": 12.4,
|
||||
"cpu_per_core": [11.2, 15.7],
|
||||
"mem_total": 33554432,
|
||||
"mem_used": 18321408,
|
||||
"swap_total": 0,
|
||||
"swap_used": 0,
|
||||
"process_count": 127,
|
||||
"hostname": "myserver",
|
||||
"cpu_temp_c": 42.5,
|
||||
"disks": [{"name":"nvme0n1p2","total":512000000000,"available":320000000000}],
|
||||
"networks": [{"name":"eth0","received":12345678,"transmitted":87654321}],
|
||||
"top_processes": [
|
||||
{"pid":1234,"name":"nginx","cpu_usage":1.2,"mem_bytes":12345678}
|
||||
],
|
||||
"gpus": null
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- process_count is merged into the main metrics on the client when processes are polled.
|
||||
- top_processes are the current top 50 (sorting in the TUI is client-side).
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
Set a token on the agent and pass it as a query param from the client:
|
||||
|
||||
Server:
|
||||
|
||||
```bash
|
||||
SOCKTOP_TOKEN=changeme socktop_agent --port 3000
|
||||
```
|
||||
|
||||
Client:
|
||||
|
||||
```bash
|
||||
socktop "ws://HOST:3000/ws?token=changeme"
|
||||
```
|
||||
|
||||
### TLS / WSS
|
||||
|
||||
For encrypted connections, enable TLS on the agent and pin the server certificate on the client.
|
||||
|
||||
Server (generates self‑signed cert and key on first run):
|
||||
|
||||
```bash
|
||||
socktop_agent --enableSSL --port 8443
|
||||
```
|
||||
|
||||
Client (trust/pin the server cert; copy cert.pem from the agent):
|
||||
|
||||
```bash
|
||||
socktop --tls-ca /path/to/agent/cert.pem wss://HOST:8443/ws
|
||||
```
|
||||
|
||||
Notes:
|
||||
- Do not copy the private key off the server; only the cert.pem is needed by clients.
|
||||
- When --tls-ca/-t is supplied, the client auto‑upgrades ws:// to wss:// to avoid protocol mismatch.
|
||||
- Hostname (SAN) verification is DISABLED by default (the cert is still pinned). Use `--verify-hostname` to enable strict SAN checking.
|
||||
- You can run multiple clients with different cert paths by passing --tls-ca per invocation.
|
||||
|
||||
---
|
||||
|
||||
## Using tmux to monitor multiple hosts
|
||||
|
||||
You can use tmux to show multiple socktop instances in a single terminal.
|
||||
|
||||

|
||||
monitoring 4 Raspberry Pis using Tmux
|
||||
|
||||
Prerequisites:
|
||||
- Install tmux (Ubuntu/Debian: `sudo apt-get install tmux`)
|
||||
|
||||
Key bindings (defaults):
|
||||
- Split left/right: Ctrl-b %
|
||||
- Split top/bottom: Ctrl-b "
|
||||
- Move between panes: Ctrl-b + Arrow keys
|
||||
- Show pane numbers: Ctrl-b q
|
||||
- Close a pane: Ctrl-b x
|
||||
- Detach from session: Ctrl-b d
|
||||
|
||||
Two panes (left/right)
|
||||
- This creates a session named "socktop", splits it horizontally, and starts two socktops.
|
||||
|
||||
```bash
|
||||
tmux new-session -d -s socktop 'socktop ws://HOST1:3000/ws' \; \
|
||||
split-window -h 'socktop ws://HOST2:3000/ws' \; \
|
||||
select-layout even-horizontal \; \
|
||||
attach
|
||||
```
|
||||
|
||||
Four panes (top-left, top-right, bottom-left, bottom-right)
|
||||
- This creates a 2x2 grid with one socktop per pane.
|
||||
|
||||
```bash
|
||||
tmux new-session -d -s socktop 'socktop ws://HOST1:3000/ws' \; \
|
||||
split-window -h 'socktop ws://HOST2:3000/ws' \; \
|
||||
select-pane -t 0 \; split-window -v 'socktop ws://HOST3:3000/ws' \; \
|
||||
select-pane -t 1 \; split-window -v 'socktop ws://HOST4:3000/ws' \; \
|
||||
select-layout tiled \; \
|
||||
attach
|
||||
```
|
||||
|
||||
Tips:
|
||||
- Replace HOST1..HOST4 (and ports) with your targets.
|
||||
- Reattach later: `tmux attach -t socktop`
|
||||
|
||||
---
|
||||
|
||||
## Platform notes
|
||||
|
||||
- Linux: fully supported (agent and client).
|
||||
- Raspberry Pi:
|
||||
- 64-bit: aarch64-unknown-linux-gnu
|
||||
- 32-bit: armv7-unknown-linux-gnueabihf
|
||||
- Windows:
|
||||
- TUI + agent can build with stable Rust; bring your own MSVC. You’re on Windows; you know the drill.
|
||||
- CPU temperature may be unavailable.
|
||||
- binary exe for both available in build artifacts under actions.
|
||||
- macOS:
|
||||
- TUI works; agent is primarily targeted at Linux. Agent will run just fine on macos for debugging but I have not documented how to run as a service, I may not given the "security" feautures with applications on macos. We will see.
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
cargo clippy --all-targets --all-features
|
||||
cargo run -p socktop -- ws://127.0.0.1:3000/ws
|
||||
# TLS (dev): first run will create certs under ~/.config/socktop_agent/tls/
|
||||
cargo run -p socktop_agent -- --enableSSL --port 8443
|
||||
```
|
||||
|
||||
### Auto-format on commit
|
||||
|
||||
A sample pre-commit hook that runs `cargo fmt --all` is provided in `.githooks/pre-commit`.
|
||||
Enable it (one-time):
|
||||
|
||||
```bash
|
||||
git config core.hooksPath .githooks
|
||||
chmod +x .githooks/pre-commit
|
||||
```
|
||||
|
||||
Every commit will then format Rust sources and restage them automatically.
|
||||
|
||||
---
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [x] Agent authentication (token)
|
||||
- [x] Hide per-thread entries; only show processes
|
||||
- [x] Sort top processes in the TUI
|
||||
- [ ] Configurable refresh intervals (client)
|
||||
- [ ] Export metrics to file
|
||||
- [x] TLS / WSS support (self‑signed server cert + client pinning)
|
||||
- [x] Split processes/disks to separate WS calls with independent cadences (already logical on client; formalize API)
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT — see LICENSE.
|
||||
|
||||
---
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
- ratatui for the TUI
|
||||
- sysinfo for system metrics
|
||||
- tokio-tungstenite for WebSockets
|
||||
See the main repository at https://github.com/jasonwitty/socktop
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
# Setting Up GitHub Pages for socktop APT Repository
|
||||
|
||||
This guide walks you through the initial setup of your APT repository on GitHub Pages using the `gh-pages` branch.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [ ] You've run `./scripts/setup-apt-repo.sh` or manually created `apt-repo/`
|
||||
- [ ] `apt-repo/` contains signed packages and metadata
|
||||
- [ ] You have a GitHub repository for socktop
|
||||
|
||||
## Step-by-Step Setup
|
||||
|
||||
### 1. Verify Your Local Repository
|
||||
|
||||
First, make sure everything is ready:
|
||||
|
||||
```bash
|
||||
# Check that apt-repo exists and has content
|
||||
ls -la apt-repo/
|
||||
|
||||
# You should see:
|
||||
# - dists/stable/Release, Release.gpg, InRelease
|
||||
# - pool/main/*.deb
|
||||
# - KEY.gpg
|
||||
# - index.html, README.md
|
||||
```
|
||||
|
||||
### 2. Create and Switch to gh-pages Branch
|
||||
|
||||
```bash
|
||||
# Create a new orphan branch (no history from main)
|
||||
git checkout --orphan gh-pages
|
||||
|
||||
# Remove all files from staging
|
||||
git rm -rf .
|
||||
```
|
||||
|
||||
**Important:** This creates a completely separate branch. Don't worry - your main branch is safe!
|
||||
|
||||
### 3. Copy APT Repository to Root
|
||||
|
||||
```bash
|
||||
# Copy CONTENTS of apt-repo to root of gh-pages
|
||||
cp -r apt-repo/* .
|
||||
|
||||
# Remove the apt-repo directory itself
|
||||
rm -rf apt-repo
|
||||
|
||||
# Verify the structure
|
||||
ls -la
|
||||
|
||||
# You should see in the current directory:
|
||||
# - dists/
|
||||
# - pool/
|
||||
# - KEY.gpg
|
||||
# - index.html
|
||||
# - README.md
|
||||
```
|
||||
|
||||
**Why root?** GitHub Pages can only serve from:
|
||||
- `/` (root) - what we're doing
|
||||
- `/docs` directory
|
||||
- NOT from custom directories like `/apt-repo`
|
||||
|
||||
### 4. Commit and Push
|
||||
|
||||
```bash
|
||||
# Add all files
|
||||
git add .
|
||||
|
||||
# Commit
|
||||
git commit -m "Initialize APT repository for GitHub Pages"
|
||||
|
||||
# Push to gh-pages branch
|
||||
git push -u origin gh-pages
|
||||
```
|
||||
|
||||
### 5. Return to Main Branch
|
||||
|
||||
```bash
|
||||
# Switch back to your main development branch
|
||||
git checkout main
|
||||
|
||||
# Verify you're back on main
|
||||
git branch
|
||||
# Should show: * main
|
||||
```
|
||||
|
||||
### 6. Enable GitHub Pages
|
||||
|
||||
1. Go to your repository on GitHub
|
||||
2. Click **Settings** (top right)
|
||||
3. Click **Pages** (left sidebar)
|
||||
4. Under "Build and deployment":
|
||||
- Source: **Deploy from a branch**
|
||||
- Branch: **gh-pages**
|
||||
- Folder: **/ (root)**
|
||||
- Click **Save**
|
||||
|
||||
### 7. Wait for Deployment
|
||||
|
||||
GitHub will deploy your site. This usually takes 1-2 minutes.
|
||||
|
||||
You can watch the progress:
|
||||
- Go to **Actions** tab
|
||||
- Look for "pages build and deployment" workflow
|
||||
|
||||
### 8. Verify Your Repository is Live
|
||||
|
||||
Once deployed, your repository will be at:
|
||||
|
||||
```
|
||||
https://YOUR-USERNAME.github.io/socktop/
|
||||
```
|
||||
|
||||
Test it:
|
||||
|
||||
```bash
|
||||
# Check the public key is accessible
|
||||
curl -I https://YOUR-USERNAME.github.io/socktop/KEY.gpg
|
||||
|
||||
# Should return: HTTP/2 200
|
||||
|
||||
# Check the Release file
|
||||
curl -I https://YOUR-USERNAME.github.io/socktop/dists/stable/Release
|
||||
|
||||
# Should return: HTTP/2 200
|
||||
```
|
||||
|
||||
### 9. Test Installation (Optional but Recommended)
|
||||
|
||||
On a Debian/Ubuntu VM or system:
|
||||
|
||||
```bash
|
||||
# Add GPG key
|
||||
curl -fsSL https://YOUR-USERNAME.github.io/socktop/KEY.gpg | \
|
||||
sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg
|
||||
|
||||
# Add repository
|
||||
echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://YOUR-USERNAME.github.io/socktop stable main" | \
|
||||
sudo tee /etc/apt/sources.list.d/socktop.list
|
||||
|
||||
# Update package lists
|
||||
sudo apt update
|
||||
|
||||
# You should see:
|
||||
# Get:1 https://YOUR-USERNAME.github.io/socktop stable InRelease [xxx B]
|
||||
|
||||
# Install packages
|
||||
sudo apt install socktop socktop-agent
|
||||
|
||||
# Verify
|
||||
socktop --version
|
||||
```
|
||||
|
||||
## Understanding the Two Branches
|
||||
|
||||
After setup, you'll have two branches:
|
||||
|
||||
### `main` branch (development)
|
||||
```
|
||||
main/
|
||||
├── src/
|
||||
├── Cargo.toml
|
||||
├── scripts/
|
||||
├── docs/
|
||||
├── apt-repo/ ← Local build artifact (not published)
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Purpose:** Source code, development, building packages
|
||||
|
||||
### `gh-pages` branch (published)
|
||||
```
|
||||
gh-pages/
|
||||
├── dists/
|
||||
├── pool/
|
||||
├── KEY.gpg
|
||||
├── index.html ← Customize this for a nice landing page!
|
||||
└── README.md
|
||||
```
|
||||
|
||||
**Purpose:** Published APT repository served by GitHub Pages
|
||||
|
||||
## Workflow Going Forward
|
||||
|
||||
### Manual Updates
|
||||
|
||||
When you release a new version:
|
||||
|
||||
```bash
|
||||
# 1. On main branch, build new packages
|
||||
git checkout main
|
||||
cargo deb --package socktop
|
||||
cargo deb --package socktop_agent
|
||||
|
||||
# 2. Update local apt-repo
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop_*.deb
|
||||
./scripts/add-package-to-repo.sh target/debian/socktop-agent_*.deb
|
||||
./scripts/sign-apt-repo.sh apt-repo stable YOUR-GPG-KEY-ID
|
||||
|
||||
# 3. Switch to gh-pages and update
|
||||
git checkout gh-pages
|
||||
cp -r apt-repo/* .
|
||||
git add .
|
||||
git commit -m "Release v1.51.0"
|
||||
git push origin gh-pages
|
||||
|
||||
# 4. Return to main
|
||||
git checkout main
|
||||
```
|
||||
|
||||
### Automated Updates (Recommended)
|
||||
|
||||
Set up GitHub Actions to do this automatically:
|
||||
|
||||
1. Add GitHub Secrets (Settings → Secrets → Actions):
|
||||
- `GPG_PRIVATE_KEY` - Your exported private key
|
||||
- `GPG_KEY_ID` - Your GPG key ID
|
||||
- `GPG_PASSPHRASE` - Your GPG passphrase (if any)
|
||||
|
||||
2. Tag and push:
|
||||
```bash
|
||||
git tag v1.51.0
|
||||
git push origin main --tags
|
||||
```
|
||||
|
||||
3. GitHub Actions will automatically:
|
||||
- Build packages for AMD64 and ARM64
|
||||
- Update apt-repo
|
||||
- Sign with your GPG key
|
||||
- Push to gh-pages
|
||||
- Create GitHub Release
|
||||
|
||||
See `.github/workflows/publish-apt-repo.yml` for details.
|
||||
|
||||
## Customizing Your GitHub Pages Site
|
||||
|
||||
The `gh-pages` branch contains `index.html` which users see when they visit:
|
||||
`https://YOUR-USERNAME.github.io/socktop/`
|
||||
|
||||
You can customize this! On the `gh-pages` branch:
|
||||
|
||||
```bash
|
||||
git checkout gh-pages
|
||||
|
||||
# Edit index.html
|
||||
nano index.html
|
||||
|
||||
# Add features, badges, screenshots, etc.
|
||||
|
||||
git add index.html
|
||||
git commit -m "Improve landing page"
|
||||
git push origin gh-pages
|
||||
|
||||
git checkout main
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "404 Not Found" on GitHub Pages
|
||||
|
||||
**Check:**
|
||||
- Settings → Pages shows "Your site is live at..."
|
||||
- Wait 2-3 minutes after pushing
|
||||
- Verify branch is `gh-pages` and folder is `/`
|
||||
- Check Actions tab for deployment errors
|
||||
|
||||
### "Repository not found" when installing
|
||||
|
||||
**Check:**
|
||||
- URL is correct: `https://USERNAME.github.io/REPO/` (no trailing /apt-repo)
|
||||
- Files exist at the URLs:
|
||||
```bash
|
||||
curl -I https://USERNAME.github.io/REPO/dists/stable/InRelease
|
||||
curl -I https://USERNAME.github.io/REPO/KEY.gpg
|
||||
```
|
||||
|
||||
### "GPG error" when installing
|
||||
|
||||
**Check:**
|
||||
- Repository is signed: `ls gh-pages/dists/stable/Release.gpg`
|
||||
- Users imported the key: `curl https://USERNAME.github.io/REPO/KEY.gpg | gpg --import`
|
||||
|
||||
### Changes not appearing
|
||||
|
||||
**Check:**
|
||||
- You committed and pushed to `gh-pages` (not `main`)
|
||||
- Wait 1-2 minutes for GitHub to redeploy
|
||||
- Clear browser cache if viewing index.html
|
||||
- For apt: `sudo apt clean && sudo apt update`
|
||||
|
||||
## Success Checklist
|
||||
|
||||
After completing this guide, you should have:
|
||||
|
||||
- [ ] `gh-pages` branch created and pushed
|
||||
- [ ] GitHub Pages enabled and deployed
|
||||
- [ ] Site accessible at `https://USERNAME.github.io/socktop/`
|
||||
- [ ] `KEY.gpg` downloadable
|
||||
- [ ] `dists/stable/InRelease` accessible
|
||||
- [ ] Packages in `pool/main/*.deb` downloadable
|
||||
- [ ] Successfully tested installation on a test system
|
||||
- [ ] Understand the workflow for future updates
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Update your main README.md** with installation instructions
|
||||
2. **Set up GitHub Actions** for automated releases
|
||||
3. **Customize index.html** on gh-pages for a nice landing page
|
||||
4. **Test on multiple architectures** (AMD64, ARM64)
|
||||
5. **Share your repository** with users
|
||||
|
||||
## Quick Reference
|
||||
|
||||
**Switch branches:**
|
||||
```bash
|
||||
git checkout main # Development
|
||||
git checkout gh-pages # Published site
|
||||
```
|
||||
|
||||
**Update published site manually:**
|
||||
```bash
|
||||
git checkout main
|
||||
# ... build packages, update apt-repo ...
|
||||
git checkout gh-pages
|
||||
cp -r apt-repo/* .
|
||||
git add . && git commit -m "Update" && git push
|
||||
git checkout main
|
||||
```
|
||||
|
||||
**Your repository URL:**
|
||||
```
|
||||
https://YOUR-USERNAME.github.io/socktop/
|
||||
```
|
||||
|
||||
**User installation command:**
|
||||
```bash
|
||||
curl -fsSL https://YOUR-USERNAME.github.io/socktop/KEY.gpg | \
|
||||
sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://YOUR-USERNAME.github.io/socktop stable main" | \
|
||||
sudo tee /etc/apt/sources.list.d/socktop.list
|
||||
sudo apt update && sudo apt install socktop socktop-agent
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Need help?** See:
|
||||
- `QUICK_START_APT_REPO.md` - Overall quick start
|
||||
- `docs/APT_REPOSITORY.md` - Comprehensive guide
|
||||
- `docs/APT_WORKFLOW.md` - Visual workflow diagrams
|
||||
@@ -0,0 +1,119 @@
|
||||
# Why We Use the gh-pages Branch
|
||||
|
||||
## The Problem
|
||||
|
||||
GitHub Pages has a limitation - it can only serve static sites from:
|
||||
|
||||
1. **`/` (root)** of a branch
|
||||
2. **`/docs`** directory of a branch
|
||||
3. **NOT** from custom directories like `/apt-repo`
|
||||
|
||||
## Why Not `/docs`?
|
||||
|
||||
When you tried to enable GitHub Pages with `apt-repo/` checked into main, you couldn't select it because:
|
||||
|
||||
```
|
||||
main/
|
||||
├── src/
|
||||
├── Cargo.toml
|
||||
├── apt-repo/ ← GitHub Pages can't serve from here!
|
||||
└── ...
|
||||
```
|
||||
|
||||
You could move it to `/docs`:
|
||||
```
|
||||
main/
|
||||
├── src/
|
||||
├── Cargo.toml
|
||||
├── docs/ ← GitHub Pages CAN serve from here
|
||||
│ ├── dists/
|
||||
│ ├── pool/
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
But this has downsides:
|
||||
- ❌ Mixed source code and published content
|
||||
- ❌ Large .deb files bloat the main branch
|
||||
- ❌ Can't easily customize the site without affecting source
|
||||
- ❌ Messy git history with binary files
|
||||
|
||||
## Why gh-pages Branch (Our Solution)
|
||||
|
||||
Using a separate `gh-pages` branch is cleaner:
|
||||
|
||||
```
|
||||
main branch (source code):
|
||||
├── src/
|
||||
├── Cargo.toml
|
||||
├── scripts/
|
||||
└── docs/ ← Documentation source
|
||||
|
||||
gh-pages branch (published):
|
||||
├── dists/
|
||||
├── pool/
|
||||
├── KEY.gpg
|
||||
├── index.html ← Customizable landing page
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### Benefits
|
||||
|
||||
✅ **Clean separation**: Source code stays in `main`, published content in `gh-pages`
|
||||
✅ **No binary bloat**: .deb files don't clutter your main branch history
|
||||
✅ **Easy automation**: GitHub Actions can push to gh-pages without affecting main
|
||||
✅ **Customizable**: You can make a beautiful landing page on gh-pages
|
||||
✅ **Standard practice**: Most GitHub Pages projects use gh-pages branch
|
||||
✅ **Root URL**: Your repo is at `https://username.github.io/socktop/` (not `/apt-repo`)
|
||||
|
||||
### Workflow
|
||||
|
||||
```
|
||||
Developer (main branch)
|
||||
↓
|
||||
Build packages
|
||||
↓
|
||||
Update apt-repo/ (local)
|
||||
↓
|
||||
Push to gh-pages branch
|
||||
↓
|
||||
GitHub Pages serves
|
||||
↓
|
||||
Users: apt install socktop
|
||||
```
|
||||
|
||||
## The Setup
|
||||
|
||||
**One-time setup:**
|
||||
```bash
|
||||
git checkout --orphan gh-pages
|
||||
git rm -rf .
|
||||
cp -r apt-repo/* .
|
||||
rm -rf apt-repo
|
||||
git add . && git commit -m "Initialize APT repository"
|
||||
git push -u origin gh-pages
|
||||
git checkout main
|
||||
```
|
||||
|
||||
**Going forward:**
|
||||
- Work on `main` branch for development
|
||||
- `gh-pages` branch gets updated by GitHub Actions (or manually)
|
||||
- Never need to switch branches manually after automation is set up!
|
||||
|
||||
## Comparison
|
||||
|
||||
| Approach | Location | URL | Pros | Cons |
|
||||
|----------|----------|-----|------|------|
|
||||
| **gh-pages branch** ✅ | gh-pages:/ | `username.github.io/socktop/` | Clean, automated, customizable | Two branches |
|
||||
| `/docs` on main | main:/docs | `username.github.io/socktop/` | One branch | Mixed content, binary bloat |
|
||||
| `/apt-repo` on main | main:/apt-repo | ❌ Not possible | - | GitHub Pages won't allow it |
|
||||
|
||||
## Conclusion
|
||||
|
||||
The `gh-pages` branch approach is:
|
||||
- The **cleanest** solution
|
||||
- The **most flexible** for customization
|
||||
- The **easiest to automate**
|
||||
- **Industry standard** for GitHub Pages
|
||||
|
||||
That's why we chose it! 🚀
|
||||
@@ -0,0 +1,43 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
Origin: socktop
|
||||
Label: socktop
|
||||
Suite: stable
|
||||
Codename: stable
|
||||
Architectures: amd64 arm64 armhf riscv64
|
||||
Components: main
|
||||
Description: socktop APT repository
|
||||
Date: Mon, 24 Aug 2026 14:30:55 +0000
|
||||
MD5Sum:
|
||||
ada07cbd3ac088cecb5dc9d08518823d 1627 main/binary-amd64/Packages
|
||||
fbb8924917960d65b5bcad003ccb90c2 830 main/binary-amd64/Packages.gz
|
||||
71b8d2e69d19d4db385bc3f2be603b72 1627 main/binary-arm64/Packages
|
||||
70831c731ff47542094fe3417e385aa6 830 main/binary-arm64/Packages.gz
|
||||
129d1b34bf48c75861a188d6ae8fba77 1611 main/binary-armhf/Packages
|
||||
54e691233b47bb1f0d89f82b00d9403f 814 main/binary-armhf/Packages.gz
|
||||
4c3fc0b399405dd682dac1318adda05f 1623 main/binary-riscv64/Packages
|
||||
15bcbe1806bf2577849090556c3a2a81 817 main/binary-riscv64/Packages.gz
|
||||
SHA256:
|
||||
88a907a84f4d292e34426d71e328561aba9658440e588f62f0f3b5d7f5c5f121 1627 main/binary-amd64/Packages
|
||||
3a87b0b38cb79d231b8ed66e1fdc9a54369d0d3f2f0686f6513cece15f0dc967 830 main/binary-amd64/Packages.gz
|
||||
84a43993bf58648174ef5bf1d4542e96f5d7903acedc0405f8f3aeab4fdbb4e7 1627 main/binary-arm64/Packages
|
||||
fd8e6a7ec2b7c438659b0fe8fa825670ccfbeb2298c01b55020cbdad2acb3313 830 main/binary-arm64/Packages.gz
|
||||
63a89cdee8e5c93867b2dd5193df162304ea97855ad68135c5c5d0753700102c 1611 main/binary-armhf/Packages
|
||||
c81f19a798757bd1806bb860aba238757edf1b902338554e30bcddba86b3c02b 814 main/binary-armhf/Packages.gz
|
||||
fa590edf01fbdd63817bd1cee4ab49d93bd47d60d74ecdae961cfa927e5b0526 1623 main/binary-riscv64/Packages
|
||||
3815e37b15c4ac150e23ce76786bfda0165e325d00b3650466442356ac39221b 817 main/binary-riscv64/Packages.gz
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQGzBAEBCgAdFiEEHnVWqAU5uDlLwoINESwaeYRl+/IFAmqMVaEACgkQESwaeYRl
|
||||
+/JqUQv+PFvgvw2yMwX1jfCeyKAfc/BmWIitVo5eOYS4P4iMqnOLGP9M44okbhgH
|
||||
Ss7l9kg13Bmtn3TdF6eWOoyfhb/Zchpf5O4xeaXLCBsaTjFtX2BAgg7Z441AkEVP
|
||||
AzaGcmbev6+R7EM3EEqk0fvVLyYHWw9qY9ADC+ArZ7GxYgVgAkIcM2V1bzjJQtOw
|
||||
dYR2XwGWiFZet62DXVsCs6g26tUyvmR062GcKmk1xQY/g9SbOqPXYP7Uou5hw+UZ
|
||||
QAY9LFnCWDz0OATclIKZzqhp7oMjWe3T96d/25lV+fQ2Cmk7ayPGaTrpeTnvCfzO
|
||||
u46DIQkkTpyalhZPcC0hgCg9tbh2rzAF6ETy+oKmYYE8wEA8wqIvJdGt1RZT/IUg
|
||||
SQEma61GavK0nBVjPjEjchT5hfTgS03YBea15lA5sZiEAD0SOV4QHxbbVmszGEaQ
|
||||
Ha4AnRLBji9Ea5E3848QTJLPq1BZ7zLvU6Tn8Nlutuh2doizSQlX3xSozvUV9BYp
|
||||
bWU/J6Ye
|
||||
=8uE3
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,26 @@
|
||||
Origin: socktop
|
||||
Label: socktop
|
||||
Suite: stable
|
||||
Codename: stable
|
||||
Architectures: amd64 arm64 armhf riscv64
|
||||
Components: main
|
||||
Description: socktop APT repository
|
||||
Date: Mon, 24 Aug 2026 14:30:55 +0000
|
||||
MD5Sum:
|
||||
ada07cbd3ac088cecb5dc9d08518823d 1627 main/binary-amd64/Packages
|
||||
fbb8924917960d65b5bcad003ccb90c2 830 main/binary-amd64/Packages.gz
|
||||
71b8d2e69d19d4db385bc3f2be603b72 1627 main/binary-arm64/Packages
|
||||
70831c731ff47542094fe3417e385aa6 830 main/binary-arm64/Packages.gz
|
||||
129d1b34bf48c75861a188d6ae8fba77 1611 main/binary-armhf/Packages
|
||||
54e691233b47bb1f0d89f82b00d9403f 814 main/binary-armhf/Packages.gz
|
||||
4c3fc0b399405dd682dac1318adda05f 1623 main/binary-riscv64/Packages
|
||||
15bcbe1806bf2577849090556c3a2a81 817 main/binary-riscv64/Packages.gz
|
||||
SHA256:
|
||||
88a907a84f4d292e34426d71e328561aba9658440e588f62f0f3b5d7f5c5f121 1627 main/binary-amd64/Packages
|
||||
3a87b0b38cb79d231b8ed66e1fdc9a54369d0d3f2f0686f6513cece15f0dc967 830 main/binary-amd64/Packages.gz
|
||||
84a43993bf58648174ef5bf1d4542e96f5d7903acedc0405f8f3aeab4fdbb4e7 1627 main/binary-arm64/Packages
|
||||
fd8e6a7ec2b7c438659b0fe8fa825670ccfbeb2298c01b55020cbdad2acb3313 830 main/binary-arm64/Packages.gz
|
||||
63a89cdee8e5c93867b2dd5193df162304ea97855ad68135c5c5d0753700102c 1611 main/binary-armhf/Packages
|
||||
c81f19a798757bd1806bb860aba238757edf1b902338554e30bcddba86b3c02b 814 main/binary-armhf/Packages.gz
|
||||
fa590edf01fbdd63817bd1cee4ab49d93bd47d60d74ecdae961cfa927e5b0526 1623 main/binary-riscv64/Packages
|
||||
3815e37b15c4ac150e23ce76786bfda0165e325d00b3650466442356ac39221b 817 main/binary-riscv64/Packages.gz
|
||||
@@ -0,0 +1,14 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQGzBAABCgAdFiEEHnVWqAU5uDlLwoINESwaeYRl+/IFAmqMVZ8ACgkQESwaeYRl
|
||||
+/JgAgwA1xKy+N7n4S4bjP1LxoLDa0fOHnxORd2dajYHkA6NqORSd2KPgWqBwtlA
|
||||
TGA8wJ8Gurdluu6kaZ8rJ55PUVZFX2qU/UsXy0Pn1Kp2NMuMhdkzXUuYI/oKILof
|
||||
TtYKqubJ4+LZvfrCdOWusDGhybA4DXaPGm+/EjJ6xKJDm0N6Ht4YhUlb9uTFH8jr
|
||||
y/hzl9Qcp2GoaDIXoLQCYPfUePHSH7JRn77uuKu3DKC3rwP2QXyBDNfWRJY0X89L
|
||||
fGBzAxgj2jE7/Gn/T3X3QGTsSAlZeuEIu88/+qwyi3kq7SeBWFf70kGHFS3RPAmh
|
||||
ULMpQe44N0H3faBIC1wER/P12NIDCi633XkL5WVwA+HvSWk8DZGu+cV4s7BcmWbD
|
||||
8KOcJe9dEoYpcGbxpZMqe0iCc6pr7vQ5FBlt0Zj0LzvONSL55kH8L7tG/uX4VXcM
|
||||
g6LLLJjm6oLWT8U8QNskOgAVxTgyZgHUVa2cAG0jZp0BErSegg38mHLs3QXtdySc
|
||||
xd4t41hM
|
||||
=OG4V
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,40 @@
|
||||
Package: socktop
|
||||
Version: 1.60.2-1
|
||||
Architecture: amd64
|
||||
Maintainer: Jason Witty <jasonpwitty+socktop@proton.me>
|
||||
Installed-Size: 3441
|
||||
Depends: libc6 (>= 2.34)
|
||||
Filename: pool/main/socktop_1.60.2-1_amd64.deb
|
||||
Size: 1313748
|
||||
MD5sum: 24517013f7e9683f2bbbbf07debdffca
|
||||
SHA1: c5c9498bfcc8a8d21342f1f4b5797e4c000462d7
|
||||
SHA256: b5d21f5f322af61e7ea6846ba337e5e48697969cf40b098d01ad4927c912d6e6
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Homepage: https://github.com/jasonwitty/socktop
|
||||
Description: Remote system monitor over WebSocket, TUI like top
|
||||
socktop is a remote system monitor with a rich terminal user interface (TUI)
|
||||
that connects to remote hosts running the socktop_agent over WebSocket. It
|
||||
provides real-time monitoring of CPU, memory, processes, and more with an
|
||||
interface similar to the traditional 'top' command.
|
||||
|
||||
Package: socktop-agent
|
||||
Version: 1.60.2-1
|
||||
Architecture: amd64
|
||||
Maintainer: Jason Witty <jasonpwitty+socktop@proton.me>
|
||||
Installed-Size: 6537
|
||||
Depends: libc6 (>= 2.34), libdrm-amdgpu1 (>= 2.4.80)
|
||||
Filename: pool/main/socktop-agent_1.60.2-1_amd64.deb
|
||||
Size: 1858208
|
||||
MD5sum: fa4f1a29b22fe191140787da50c70cd1
|
||||
SHA1: b310e7f5a29be4d18add88a6b30437eb34d2e6a1
|
||||
SHA256: 328975156e28ffc2d38a23c317406b9220f0062992f97bfea327403ba6d26d71
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Homepage: https://github.com/jasonwitty/socktop
|
||||
Description: Socktop agent daemon. Serves host metrics over WebSocket.
|
||||
socktop_agent is the daemon component that runs on remote hosts to collect and
|
||||
serve system metrics over WebSocket. It gathers CPU, memory, disk, network,
|
||||
GPU, and process information that can be monitored remotely by the socktop TUI
|
||||
client.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Archive: stable
|
||||
Component: main
|
||||
Origin: socktop
|
||||
Label: socktop
|
||||
Architecture: amd64
|
||||
@@ -0,0 +1,40 @@
|
||||
Package: socktop
|
||||
Version: 1.60.2-1
|
||||
Architecture: arm64
|
||||
Maintainer: Jason Witty <jasonpwitty+socktop@proton.me>
|
||||
Installed-Size: 2994
|
||||
Depends: libc6 (>= 2.34)
|
||||
Filename: pool/main/socktop_1.60.2-1_arm64.deb
|
||||
Size: 1176428
|
||||
MD5sum: 6c628e55b118550964fdd3429ade9013
|
||||
SHA1: 814407491af72cc8c03dfc4aca1fcd29676d84e7
|
||||
SHA256: fb3f29fe439d7e8a6813c52811a4acb9dc5a390acbbe5c8b5a7d77301bf7df39
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Homepage: https://github.com/jasonwitty/socktop
|
||||
Description: Remote system monitor over WebSocket, TUI like top
|
||||
socktop is a remote system monitor with a rich terminal user interface (TUI)
|
||||
that connects to remote hosts running the socktop_agent over WebSocket. It
|
||||
provides real-time monitoring of CPU, memory, processes, and more with an
|
||||
interface similar to the traditional 'top' command.
|
||||
|
||||
Package: socktop-agent
|
||||
Version: 1.60.2-1
|
||||
Architecture: arm64
|
||||
Maintainer: Jason Witty <jasonpwitty+socktop@proton.me>
|
||||
Installed-Size: 5158
|
||||
Depends: libc6 (>= 2.34), libdrm-amdgpu1 (>= 2.4.80)
|
||||
Filename: pool/main/socktop-agent_1.60.2-1_arm64.deb
|
||||
Size: 1648768
|
||||
MD5sum: d40c11e1a82a4deee69a8f09b99b8a3c
|
||||
SHA1: bb17940a085d9cdda0d0ae26aa73843f3b293705
|
||||
SHA256: 9f0779dafe9e2c5029c65201e2d45abb2cc9b9dfae38deb6d650f6c9a5fd07ce
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Homepage: https://github.com/jasonwitty/socktop
|
||||
Description: Socktop agent daemon. Serves host metrics over WebSocket.
|
||||
socktop_agent is the daemon component that runs on remote hosts to collect and
|
||||
serve system metrics over WebSocket. It gathers CPU, memory, disk, network,
|
||||
GPU, and process information that can be monitored remotely by the socktop TUI
|
||||
client.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
Package: socktop
|
||||
Version: 1.60.2-1
|
||||
Architecture: armhf
|
||||
Maintainer: Jason Witty <jasonpwitty+socktop@proton.me>
|
||||
Installed-Size: 2764
|
||||
Depends: libc6:armhf (>= 2.35)
|
||||
Filename: pool/main/socktop_1.60.2-1_armhf.deb
|
||||
Size: 1029920
|
||||
MD5sum: 731d71c8450006624db51f802a1b75fa
|
||||
SHA1: 7a797ecb089208171bc762a2602af8048b9d74fa
|
||||
SHA256: bfd6d29c18826ed20a9f0e3af2e0f5cc2d24dd23f621110f9d58aed60f7ca1a5
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Homepage: https://github.com/jasonwitty/socktop
|
||||
Description: Remote system monitor over WebSocket, TUI like top
|
||||
socktop is a remote system monitor with a rich terminal user interface (TUI)
|
||||
that connects to remote hosts running the socktop_agent over WebSocket. It
|
||||
provides real-time monitoring of CPU, memory, processes, and more with an
|
||||
interface similar to the traditional 'top' command.
|
||||
|
||||
Package: socktop-agent
|
||||
Version: 1.60.2-1
|
||||
Architecture: armhf
|
||||
Maintainer: Jason Witty <jasonpwitty+socktop@proton.me>
|
||||
Installed-Size: 3821
|
||||
Depends: libc6:armhf (>= 2.35)
|
||||
Filename: pool/main/socktop-agent_1.60.2-1_armhf.deb
|
||||
Size: 1462340
|
||||
MD5sum: b987e05b88a9a32fb3379c54413a1eb0
|
||||
SHA1: c751d0bf6ced067c667895f36379df4bc7b1170c
|
||||
SHA256: c2bcce2e679d96cc9076d118abd9a766ed413f306d88dcc59912814c1962ba04
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Homepage: https://github.com/jasonwitty/socktop
|
||||
Description: Socktop agent daemon. Serves host metrics over WebSocket.
|
||||
socktop_agent is the daemon component that runs on remote hosts to collect and
|
||||
serve system metrics over WebSocket. It gathers CPU, memory, disk, network,
|
||||
GPU, and process information that can be monitored remotely by the socktop TUI
|
||||
client.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
Package: socktop
|
||||
Version: 1.60.2-1
|
||||
Architecture: riscv64
|
||||
Maintainer: Jason Witty <jasonpwitty+socktop@proton.me>
|
||||
Installed-Size: 2668
|
||||
Depends: libc6:riscv64 (>= 2.35)
|
||||
Filename: pool/main/socktop_1.60.2-1_riscv64.deb
|
||||
Size: 1166192
|
||||
MD5sum: 11e89c1f7909fc90047a74d2880d1362
|
||||
SHA1: 4089962ff3864209a026b585fe2b6490cfe014a2
|
||||
SHA256: e1fad743c74934a11e49808d0bba80c26f05e6d75c231f239870866ba50e1e38
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Homepage: https://github.com/jasonwitty/socktop
|
||||
Description: Remote system monitor over WebSocket, TUI like top
|
||||
socktop is a remote system monitor with a rich terminal user interface (TUI)
|
||||
that connects to remote hosts running the socktop_agent over WebSocket. It
|
||||
provides real-time monitoring of CPU, memory, processes, and more with an
|
||||
interface similar to the traditional 'top' command.
|
||||
|
||||
Package: socktop-agent
|
||||
Version: 1.60.2-1
|
||||
Architecture: riscv64
|
||||
Maintainer: Jason Witty <jasonpwitty+socktop@proton.me>
|
||||
Installed-Size: 3846
|
||||
Depends: libc6:riscv64 (>= 2.35)
|
||||
Filename: pool/main/socktop-agent_1.60.2-1_riscv64.deb
|
||||
Size: 1637096
|
||||
MD5sum: 98347f203e942073464ff8b8d16796bb
|
||||
SHA1: dec2ae6fdd5bea71f43f9e24842a0851150e24fd
|
||||
SHA256: fd4070c6e0b29adf5bb9de32f098431e9dcf7456e1fc7f4460a5e9a5708496cc
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Homepage: https://github.com/jasonwitty/socktop
|
||||
Description: Socktop agent daemon. Serves host metrics over WebSocket.
|
||||
socktop_agent is the daemon component that runs on remote hosts to collect and
|
||||
serve system metrics over WebSocket. It gathers CPU, memory, disk, network,
|
||||
GPU, and process information that can be monitored remotely by the socktop TUI
|
||||
client.
|
||||
|
||||
|
Before Width: | Height: | Size: 775 KiB |
|
Before Width: | Height: | Size: 879 KiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 616 KiB |
|
Before Width: | Height: | Size: 2.4 MiB |
@@ -1,18 +0,0 @@
|
||||
[Unit]
|
||||
Description=Socktop agent
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/socktop_agent --port 3000
|
||||
Environment=RUST_LOG=info
|
||||
# Optional auth:
|
||||
# Environment=SOCKTOP_TOKEN=changeme
|
||||
Restart=on-failure
|
||||
User=socktop
|
||||
Group=socktop
|
||||
NoNewPrivileges=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
Before Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 2.3 MiB |
@@ -0,0 +1,364 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>socktop APT Repository</title>
|
||||
<style>
|
||||
/* Catppuccin Frappe Color Palette */
|
||||
:root {
|
||||
--ctp-base: #303446;
|
||||
--ctp-mantle: #292c3c;
|
||||
--ctp-crust: #232634;
|
||||
--ctp-text: #c6d0f5;
|
||||
--ctp-subtext1: #b5bfe2;
|
||||
--ctp-subtext0: #a5adce;
|
||||
--ctp-overlay2: #949cbb;
|
||||
--ctp-overlay1: #838ba7;
|
||||
--ctp-overlay0: #737994;
|
||||
--ctp-surface2: #626880;
|
||||
--ctp-surface1: #51576d;
|
||||
--ctp-surface0: #414559;
|
||||
--ctp-lavender: #babbf1;
|
||||
--ctp-blue: #8caaee;
|
||||
--ctp-sapphire: #85c1dc;
|
||||
--ctp-sky: #99d1db;
|
||||
--ctp-teal: #81c8be;
|
||||
--ctp-green: #a6d189;
|
||||
--ctp-yellow: #e5c890;
|
||||
--ctp-peach: #ef9f76;
|
||||
--ctp-maroon: #ea999c;
|
||||
--ctp-red: #e78284;
|
||||
--ctp-mauve: #ca9ee6;
|
||||
--ctp-pink: #f4b8e4;
|
||||
--ctp-flamingo: #eebebe;
|
||||
--ctp-rosewater: #f2d5cf;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
"Helvetica Neue", Arial, sans-serif;
|
||||
background-color: var(--ctp-base);
|
||||
color: var(--ctp-text);
|
||||
line-height: 1.6;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
background-color: var(--ctp-mantle);
|
||||
border-radius: 12px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--ctp-blue);
|
||||
font-size: 2.5em;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 3px solid var(--ctp-surface0);
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
h2 {
|
||||
color: var(--ctp-mauve);
|
||||
font-size: 1.8em;
|
||||
margin-top: 35px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
h3 {
|
||||
color: var(--ctp-sapphire);
|
||||
font-size: 1.3em;
|
||||
margin-top: 25px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 15px;
|
||||
color: var(--ctp-subtext0);
|
||||
}
|
||||
.subtitle {
|
||||
color: var(--ctp-subtext1);
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: var(--ctp-surface0);
|
||||
color: var(--ctp-green);
|
||||
padding: 3px 8px;
|
||||
border-radius: 5px;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
pre {
|
||||
background-color: var(--ctp-crust);
|
||||
border: 1px solid var(--ctp-surface0);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
overflow-x: auto;
|
||||
margin: 15px 0;
|
||||
position: relative;
|
||||
padding-top: 18px; /* leave space for top-right button */
|
||||
}
|
||||
pre code {
|
||||
background: transparent;
|
||||
color: var(--ctp-text);
|
||||
display: block;
|
||||
white-space: pre;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
/* Copy button styles */
|
||||
.copy-btn {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
background: var(--ctp-surface1);
|
||||
color: var(--ctp-text);
|
||||
border: 1px solid var(--ctp-surface2);
|
||||
padding: 6px 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition:
|
||||
background 0.12s ease,
|
||||
transform 0.08s ease;
|
||||
}
|
||||
.copy-btn:hover {
|
||||
background: var(--ctp-surface2);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.copy-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.copy-btn.copied {
|
||||
background: var(--ctp-green);
|
||||
color: var(--ctp-crust);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
background-color: var(--ctp-surface1);
|
||||
color: var(--ctp-text);
|
||||
padding: 5px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.9em;
|
||||
margin: 5px 5px 5px 0;
|
||||
border: 1px solid var(--ctp-surface2);
|
||||
}
|
||||
.badge.arch {
|
||||
background-color: var(--ctp-surface0);
|
||||
color: var(--ctp-lavender);
|
||||
}
|
||||
|
||||
.note {
|
||||
background-color: var(--ctp-surface0);
|
||||
border-left: 4px solid var(--ctp-yellow);
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.note strong {
|
||||
color: var(--ctp-yellow);
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 50px;
|
||||
padding-top: 20px;
|
||||
border-top: 2px solid var(--ctp-surface0);
|
||||
text-align: center;
|
||||
color: var(--ctp-overlay1);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.command-comment {
|
||||
color: var(--ctp-overlay1);
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.highlight-blue {
|
||||
color: var(--ctp-blue);
|
||||
}
|
||||
.highlight-green {
|
||||
color: var(--ctp-green);
|
||||
}
|
||||
.highlight-yellow {
|
||||
color: var(--ctp-yellow);
|
||||
}
|
||||
.highlight-mauve {
|
||||
color: var(--ctp-mauve);
|
||||
}
|
||||
.highlight-peach {
|
||||
color: var(--ctp-peach);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 25px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>socktop APT Repository</h1>
|
||||
<p class="subtitle">
|
||||
System monitor with remote agent support for Linux systems
|
||||
</p>
|
||||
|
||||
<h2>📦 Quick Installation</h2>
|
||||
<p>Add this repository to your Debian/Ubuntu system:</p>
|
||||
|
||||
<h3>Step 1: Add GPG Key</h3>
|
||||
<pre><code># Add the repository's GPG signing key
|
||||
curl -fsSL https://jasonwitty.github.io/socktop/KEY.gpg | \
|
||||
sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg</code></pre>
|
||||
|
||||
<h3>Step 2: Add Repository</h3>
|
||||
<pre><code># Add the APT repository to your sources
|
||||
echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://jasonwitty.github.io/socktop stable main" | \
|
||||
sudo tee /etc/apt/sources.list.d/socktop.list</code></pre>
|
||||
|
||||
<h3>Step 3: Install</h3>
|
||||
<pre><code># Update package lists and install
|
||||
sudo apt update
|
||||
sudo apt install socktop socktop-agent</code></pre>
|
||||
|
||||
<h2>📋 What's Included</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<strong class="highlight-blue">socktop</strong> - Terminal
|
||||
UI client for monitoring systems
|
||||
</li>
|
||||
<li>
|
||||
<strong class="highlight-mauve">socktop-agent</strong> -
|
||||
Background agent that reports system metrics
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="note">
|
||||
<strong>Note:</strong> The agent package automatically installs
|
||||
and configures a systemd service. Enable it with:
|
||||
<code>sudo systemctl enable --now socktop-agent</code>
|
||||
</div>
|
||||
|
||||
<h2>🏗️ Supported Architectures</h2>
|
||||
<div>
|
||||
<span class="badge arch">amd64</span>
|
||||
<span class="badge arch">arm64</span>
|
||||
<span class="badge arch">armhf</span>
|
||||
<span class="badge arch">riscv64</span>
|
||||
</div>
|
||||
|
||||
<h2>🔧 Usage</h2>
|
||||
<p>After installation:</p>
|
||||
<pre><code># Start the TUI client
|
||||
socktop
|
||||
|
||||
# Connect to a remote agent
|
||||
socktop ws://hostname:3000
|
||||
|
||||
# Start the agent (if not using systemd)
|
||||
socktop_agent</code></pre>
|
||||
|
||||
<h2>🔗 Links</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/jasonwitty/socktop"
|
||||
>Source Code on GitHub</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/jasonwitty/socktop/issues"
|
||||
>Report Issues</a
|
||||
>
|
||||
</li>
|
||||
<li><a href="README.md">Repository Documentation</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">
|
||||
<p>Hosted on GitHub Pages | Packages signed with GPG</p>
|
||||
<p>
|
||||
Theme:
|
||||
<a href="https://github.com/catppuccin/catppuccin"
|
||||
>Catppuccin Frappe</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Attach copy buttons to all <pre> blocks and enable copy-to-clipboard.
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const pres = document.querySelectorAll("pre");
|
||||
pres.forEach((pre) => {
|
||||
// Create button
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
btn.className = "copy-btn";
|
||||
btn.setAttribute("aria-label", "Copy code to clipboard");
|
||||
// Use emoji for simplicity; you can replace with SVG if desired
|
||||
btn.innerText = "📋";
|
||||
|
||||
// Append to pre
|
||||
pre.appendChild(btn);
|
||||
|
||||
// Click handler
|
||||
btn.addEventListener("click", async (e) => {
|
||||
e.stopPropagation();
|
||||
const code = pre.querySelector("code");
|
||||
const text = code ? code.innerText : pre.innerText;
|
||||
try {
|
||||
if (!navigator.clipboard) {
|
||||
// Fallback method
|
||||
const textarea =
|
||||
document.createElement("textarea");
|
||||
textarea.value = text;
|
||||
textarea.style.position = "fixed";
|
||||
textarea.style.left = "-9999px";
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(textarea);
|
||||
} else {
|
||||
await navigator.clipboard.writeText(text);
|
||||
}
|
||||
// feedback
|
||||
btn.classList.add("copied");
|
||||
const prior = btn.innerText;
|
||||
btn.innerText = "✓ Copied";
|
||||
setTimeout(() => {
|
||||
btn.classList.remove("copied");
|
||||
btn.innerText = "📋";
|
||||
}, 1800);
|
||||
} catch (err) {
|
||||
btn.innerText = "✖";
|
||||
setTimeout(() => (btn.innerText = "📋"), 1500);
|
||||
console.error("Copy failed", err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,8 +0,0 @@
|
||||
socktop_agent: TLS enabled. Listening on wss://0.0.0.0:8433/ws
|
||||
socktop_agent: TLS enabled. Listening on wss://0.0.0.0:8433/ws
|
||||
socktop_agent: TLS enabled. Listening on wss://0.0.0.0:8433/ws
|
||||
Error: Address already in use (os error 98)
|
||||
socktop_agent: TLS enabled. Listening on wss://0.0.0.0:8433/ws
|
||||
Error: Address already in use (os error 98)
|
||||
socktop_agent: TLS enabled. Listening on wss://0.0.0.0:8443/ws
|
||||
socktop_agent: TLS enabled. Listening on wss://0.0.0.0:8443/ws
|
||||