Initial BitNet s9pk package with SSH access

This commit is contained in:
GERTY
2026-05-12 22:31:18 +00:00
commit 6e8a8f5b59
10 changed files with 429 additions and 0 deletions

26
Dockerfile Normal file
View File

@@ -0,0 +1,26 @@
# BitNet s9pk - Extended with SSH access
FROM ghcr.io/kth8/bitnet:latest
# Install OpenSSH server and dependencies
RUN apt-get update && \
apt-get install -y openssh-server && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Create SSH directory and configure
RUN mkdir -p /var/run/sshd /root/.ssh && \
chmod 700 /root/.ssh
# Configure SSH
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config && \
sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config && \
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
# Create entrypoint script
COPY docker_entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker_entrypoint.sh
EXPOSE 22
ENTRYPOINT ["/usr/local/bin/docker_entrypoint.sh"]
CMD ["/usr/sbin/sshd", "-D"]

29
Makefile Normal file
View File

@@ -0,0 +1,29 @@
# BitNet s9pk Makefile
PKG_ID := bitnet
PKG_VERSION := 1.0.0
TS_FILES := $(shell find . -name '*.ts' 2>/dev/null)
.PHONY: all clean install
# Default image
all: $(PKG_ID).s9pk
install: $(PKG_ID).s9pk
start-cli package install $(PKG_ID).s9pk
clean:
rm -f $(PKG_ID).s9pk
rm -f image.tar
# Build Docker image using remote Docker on MacBook
image.tar: Dockerfile docker_entrypoint.sh
@echo "Building Docker image on remote Docker (macbook)..."
docker -H ssh://macbook build --platform linux/amd64 --tag start9/$(PKG_ID)/main:$(PKG_VERSION) -o type=docker,dest=image.tar .
# Pack the s9pk
$(PKG_ID).s9pk: manifest.yaml image.tar instructions.md scripts/*.sh
@echo "Packing s9pk..."
start-cli s9pk pack \
--arch aarch64 \
--arch x86_64 \
.

105
README.md Normal file
View File

@@ -0,0 +1,105 @@
# BitNet s9pk Package
StartOS package for BitNet LLM with SSH access.
## Project Structure
```
bitnet-s9pk/
├── Dockerfile # Extended BitNet image with SSH
├── docker_entrypoint.sh # Entrypoint script for SSH setup
├── manifest.yaml # StartOS package manifest
├── instructions.md # User-facing instructions
├── Makefile # Build automation
├── scripts/
│ ├── config_get.sh # Config schema
│ ├── config_set.sh # Config application
│ ├── properties.sh # Package properties
│ └── health_check.sh # Health check script
└── assets/
└── icon.png # Package icon (TODO)
```
## Prerequisites
- Docker access (local or remote via SSH to MacBook)
- `start-cli` installed and authenticated
- Developer key at `/data/.startos/developer.key.pem`
## Building
### Option 1: Using Makefile (Recommended)
```bash
cd /data/.openclaw/workspace/bitnet-s9pk
make
```
This will:
1. Build the Docker image on remote Docker (MacBook)
2. Export it as `image.tar`
3. Pack everything into `bitnet.s9pk`
### Option 2: Manual Build
```bash
# Build image on MacBook
docker -H ssh://macbook build --platform linux/amd64 \
--tag start9/bitnet/main:1.0.0 \
-o type=docker,dest=image.tar .
# Pack the s9pk
start-cli s9pk pack --arch aarch64 --arch x86_64 .
```
## Installing
```bash
# Install on your StartOS server
start-cli package install bitnet.s9pk
# Or use make
make install
```
## Configuration After Install
1. Go to BitNet service in StartOS UI
2. Navigate to **Config** tab
3. Paste your SSH public key
4. Save and restart the service
## Connecting via SSH
```bash
# Via Tor (get address from Interfaces tab)
ssh -o ProxyCommand="nc -x localhost:9050 %h %p" root@your-bitnet-address.onion
# Via LAN
ssh root@your-server-lan-ip -p <port>
```
## Using BitNet
Once connected:
```bash
# Run inference
python3 /BitNet/run_inference.py -m ggml-model-i2_s.gguf -p "Hello, world!"
# See help
python3 /BitNet/run_inference.py --help
```
## TODO
- [ ] Add proper icon.png (512x512)
- [ ] Test on actual StartOS hardware
- [ ] Add model download action
- [ ] Volume mount for custom models
## References
- BitNet: https://github.com/microsoft/BitNet
- Container: https://github.com/kth8/bitnet
- StartOS Docs: https://docs.start9.com/latest/developer-docs/

17
docker_entrypoint.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
set -e
# Setup SSH authorized keys from environment variable
if [ -n "$SSH_AUTHORIZED_KEYS" ]; then
echo "$SSH_AUTHORIZED_KEYS" > /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
echo "SSH authorized keys configured"
fi
# Generate host keys if they don't exist
if [ ! -f /etc/ssh/ssh_host_rsa_key ]; then
ssh-keygen -A
fi
# Execute the command passed to the container
exec "$@"

66
instructions.md Normal file
View File

@@ -0,0 +1,66 @@
# BitNet LLM - Instructions
## Getting Started
BitNet is a CPU-based large language model inference engine. This package provides SSH access so you can interact with the model directly.
### Requirements
- **CPU with AVX2 support** (Intel Haswell or AMD Excavator or newer)
- Check support: SSH into your StartOS server and run `grep -o 'avx2' /proc/cpuinfo`
### Configuration
1. After installation, go to **Config** tab
2. Paste your SSH public key into the "SSH Authorized Keys" field
3. Save configuration
4. Restart the service
### Connecting via SSH
Get your Tor address from the **Interfaces** tab, then:
```bash
ssh -o ProxyCommand="nc -x localhost:9050 %h %p" root@your-bitnet-address.onion
```
Or via LAN (if configured):
```bash
ssh root@your-server-ip -p <bitnet-ssh-port>
```
### Using BitNet
Once connected via SSH:
```bash
# Run inference with default model
python3 /BitNet/run_inference.py -m ggml-model-i2_s.gguf -p "Your prompt here"
# See all options
python3 /BitNet/run_inference.py --help
# Use custom model (mount in /root/models)
python3 /BitNet/run_inference.py -m /root/models/your-model.gguf -p "Your prompt"
```
### Custom Models
1. Download GGUF models from Hugging Face
2. Upload them via File Browser or SCP to `/root/models/`
3. Reference them in your inference commands
### Performance
This runs entirely on CPU using AVX2 instructions. Performance depends on your server's CPU speed and core count. The default 2B parameter model is lightweight and should run reasonably well on modern hardware.
## Troubleshooting
- **Can't connect via SSH**: Verify your public key is correctly configured
- **"Illegal instruction" errors**: Your CPU doesn't support AVX2
- **Slow inference**: Normal for CPU-based inference; consider a smaller model or faster CPU
## Support
- Upstream: https://github.com/microsoft/BitNet
- Container: https://github.com/kth8/bitnet

121
manifest.yaml Normal file
View File

@@ -0,0 +1,121 @@
id: bitnet
version: 1.0.0
title: BitNet LLM
description:
short: Run BitNet LLM inference on CPU
long: |
BitNet is a CPU-based large language model inference engine from Microsoft.
This package runs the bitnet-b1.58-2B-4T model and provides SSH access for
interactive use. Requires AVX2 CPU support (Intel Haswell or newer).
release-notes: |
Initial release with SSH access enabled.
license: Apache-2.0
wrapper-repo: https://github.com/kth8/bitnet
upstream-repo: https://github.com/microsoft/BitNet
support-site: https://github.com/kth8/bitnet/issues
# No dependencies on other packages
dependencies: {}
# Docker image configuration
containers:
main:
image: main
mounts:
main: /root
# Volume for persistent data (models, etc.)
volumes:
main:
type: data
# Network interfaces
interfaces:
ssh:
name: SSH
description: SSH access to BitNet container
tor-config:
port-mapping:
22: "22"
lan-config:
443:
ssl: false
internal: 22
ui: false
protocols:
- tcp
- http
# Configuration options
config:
get:
type: script
set:
type: script
properties:
type: script
# Health check - verify sshd is running
health-checks:
main:
name: SSH Service
success-message: SSH server is running and ready for connections
type: script
# Actions for the user
actions:
run-inference:
name: Run Inference
description: Run a test inference query
warning: null
allowed-statuses:
- running
implementation:
type: docker
image: main
system: false
entrypoint: python3
args:
- /BitNet/run_inference.py
- -m
- ggml-model-i2_s.gguf
- -p
- "What is the meaning of life?"
mounts:
main: /root
io-format: json
backup:
create:
type: docker
image: compat
system: true
entrypoint: compat
args:
- duplicity
- create
- /mnt/backup
- /root/data
mounts:
BACKUP: /mnt/backup
main: /root/data
restore:
type: docker
image: compat
system: true
entrypoint: compat
args:
- duplicity
- restore
- /mnt/backup
- /root/data
mounts:
BACKUP: /mnt/backup
main: /root/data
migrations:
from: {}
to: {}

16
scripts/config_get.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
set -e
# Return current configuration as JSON
cat <<EOF
{
"ssh-keys": {
"type": "textarea",
"name": "SSH Authorized Keys",
"description": "Paste your SSH public key(s) here, one per line",
"nullable": false,
"default": "",
"masked": false
}
}
EOF

12
scripts/config_set.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
set -e
# Read config from stdin
SSH_KEYS=$(jq -r '.["ssh-keys"]' /dev/stdin)
# Save to persistent volume
mkdir -p /root/config
echo "$SSH_KEYS" > /root/config/authorized_keys
# Return success
echo "{}"

10
scripts/health_check.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
set -e
# Check if SSH daemon is running
if pgrep -x sshd > /dev/null; then
exit 0
else
echo "SSH daemon is not running"
exit 1
fi

27
scripts/properties.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
set -e
# Return package properties as JSON
cat <<EOF
{
"version": "1.0.0",
"data": {
"Model": {
"type": "string",
"value": "bitnet-b1.58-2B-4T",
"description": "Default LLM model",
"copyable": false,
"qr": false,
"masked": false
},
"CPU Requirements": {
"type": "string",
"value": "AVX2 support required",
"description": "Intel Haswell or AMD Excavator or newer",
"copyable": false,
"qr": false,
"masked": false
}
}
}
EOF