archy/neode-ui/PACKAGING_S9PK_GUIDE.md
2026-01-24 22:59:20 +00:00

404 lines
8.5 KiB
Markdown

# Packaging Apps for Neode/StartOS
This guide explains how to package containerized applications (like nostrdevs/atob) as `.s9pk` files for installation on Neode.
## What is an S9PK?
An `.s9pk` file is a package format for Neode/StartOS that contains:
- **Manifest** (metadata, dependencies, interfaces)
- **Docker Images** (your containerized app)
- **Icon** (PNG/WEBP/JPG)
- **License** (LICENSE.md)
- **Instructions** (INSTRUCTIONS.md)
- **Configuration** (optional config.yaml)
- **Actions** (optional scripts for user actions)
## Prerequisites
1. **Install StartOS SDK** (needed for packing):
```bash
# Clone the Neode repo (you already have this)
cd /Users/tx1138/Code/Neode
# Build the SDK
cd core
cargo build --release --bin startos
# The binary will be at: target/release/startos
```
2. **Docker** for building container images
## Creating an S9PK for nostrdevs/atob
### Step 1: Create Package Directory Structure
```bash
mkdir -p ~/atob-package
cd ~/atob-package
```
Create the following structure:
```
atob-package/
├── manifest.yaml # Package metadata
├── LICENSE.md # License file
├── INSTRUCTIONS.md # User instructions
├── icon.png # 512x512 icon
├── docker_images/ # Docker image archive
│ └── aarch64.tar # or x86_64.tar
└── scripts/
└── procedures/
└── main.ts # Main entry point
```
### Step 2: Create manifest.yaml
```yaml
id: atob
title: "ATOB"
version: "0.1.0"
release-notes: "Initial release"
license: MIT
wrapper-repo: "https://github.com/nostrdevs/atob"
upstream-repo: "https://github.com/nostrdevs/atob"
support-site: "https://github.com/nostrdevs/atob/issues"
marketing-site: "https://github.com/nostrdevs/atob"
donation-url: null
description:
short: "ATOB - A containerized application for Nostr"
long: |
ATOB is a containerized application designed for the Nostr ecosystem.
This package runs ATOB on your Neode server with automatic configuration.
# Assets
assets:
license: LICENSE.md
icon: icon.png
instructions: INSTRUCTIONS.md
docker-images: docker_images
# Main container
main:
type: docker
image: main
entrypoint: "docker_entrypoint.sh"
args: []
mounts:
main: /data
# Volumes
volumes:
main:
type: data
# Interfaces (exposed services)
interfaces:
main:
name: Web Interface
description: Main ATOB web interface
tor-config:
port-mapping:
80: "80"
lan-config:
443:
ssl: true
internal: 80
ui: true
protocols:
- tcp
- http
# Health checks
health-checks:
web-ui:
name: Web Interface
success-message: "ATOB is ready!"
type: docker
image: main
entrypoint: "check-web.sh"
args: []
io-format: yaml
inject: true
# Configuration (optional)
config: ~
# Properties
properties: ~
# Dependencies
dependencies: {}
# Backup configuration
backup:
create:
type: docker
image: compat
system: true
entrypoint: compat
args:
- duplicity
- create
- /mnt/backup
- /data
mounts:
BACKUP: /mnt/backup
main: /data
restore:
type: docker
image: compat
system: true
entrypoint: compat
args:
- duplicity
- restore
- /mnt/backup
- /data
mounts:
BACKUP: /mnt/backup
main: /data
# Migrations (for updates)
migrations:
from:
"*":
type: none
to:
"*":
type: none
```
### Step 3: Create LICENSE.md
Copy your project's license or create a simple one:
```markdown
# MIT License
Copyright (c) 2025 Nostr Devs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction...
```
### Step 4: Create INSTRUCTIONS.md
```markdown
# ATOB Instructions
## Getting Started
1. After installation, ATOB will be available at the interface URL
2. Access it through the Neode dashboard
3. Configuration is automatic
## Usage
[Add specific instructions for your app]
## Support
For issues, visit: https://github.com/nostrdevs/atob/issues
```
### Step 5: Add an Icon
Create or download a 512x512 PNG icon and save it as `icon.png`
### Step 6: Export Docker Image
```bash
# Build your Docker image
cd /path/to/atob
docker build -t atob:latest .
# Save the image
mkdir -p ~/atob-package/docker_images
docker save atob:latest -o ~/atob-package/docker_images/$(uname -m).tar
# The filename should match your architecture:
# - x86_64.tar for Intel/AMD
# - aarch64.tar for ARM64/Apple Silicon
```
### Step 7: Create scripts/procedures/main.ts
This is the entry point for your service:
```typescript
import { types as T, matches, YAML } from "../deps.ts";
// This is the main entry point for your service
export const main: T.ExpectedExports.main = async (effects: T.Effects) => {
return await effects.createContainer({
image: "main",
entrypoint: ["/bin/sh"],
mounts: {
main: "/data",
},
});
};
// Properties that will be displayed in the UI
export const properties: T.ExpectedExports.properties = async (
effects: T.Effects
) => {
return {
version: "0.1.0",
"Automatic TOR Address": {
type: "string",
value: effects.interfaces.main.torAddress,
qr: true,
copyable: true,
masked: false,
},
};
};
// Health check
export const health: T.ExpectedExports.health = async (effects: T.Effects) => {
return await effects.health.checkWebUrl("http://main.embassy:80");
};
```
### Step 8: Build the S9PK
```bash
# Navigate to your package directory
cd ~/atob-package
# Use the StartOS CLI to pack it
/Users/tx1138/Code/Neode/core/target/release/startos pack
# This will create: atob.s9pk
```
### Step 9: Install on Neode
**Option A: Via CLI (Direct)**
```bash
# Copy the .s9pk to your Neode server
scp atob.s9pk user@neode-server:/tmp/
# SSH into the server
ssh user@neode-server
# Install using CLI
startos package.sideload /tmp/atob.s9pk
```
**Option B: Via UI (Once Marketplace is Connected)**
1. Navigate to Marketplace in Neode UI
2. Click "Sideload Package"
3. Upload `atob.s9pk`
4. Wait for installation to complete
## Testing Your Package
### Validate Before Installing
```bash
# Inspect the package without installing
/Users/tx1138/Code/Neode/core/target/release/startos inspect atob.s9pk
```
### Development Workflow
1. **Make changes** to your manifest or scripts
2. **Rebuild** the s9pk: `startos pack`
3. **Uninstall** old version: `startos package.uninstall atob`
4. **Install** new version: `startos package.sideload atob.s9pk`
## Advanced Features
### Adding Configuration Options
Add to `manifest.yaml`:
```yaml
config:
get:
type: script
set:
type: script
# Then create scripts/procedures/getConfig.ts and setConfig.ts
```
### Adding User Actions
```yaml
actions:
restart-service:
name: "Restart Service"
description: "Manually restart the ATOB service"
warning: "This will temporarily interrupt service"
allowed-statuses:
- running
implementation:
type: docker
image: main
entrypoint: "restart.sh"
```
### Multi-Architecture Support
Build for multiple architectures:
```bash
# Build for x86_64
docker buildx build --platform linux/amd64 -t atob:amd64 .
docker save atob:amd64 -o docker_images/x86_64.tar
# Build for ARM64
docker buildx build --platform linux/arm64 -t atob:arm64 .
docker save atob:arm64 -o docker_images/aarch64.tar
```
## Resources
- **StartOS Package Manifest Schema**: [Official Docs](https://docs.start9.com)
- **Example Packages**: `/Users/tx1138/Code/Neode/core/startos/test/`
- **SDK Reference**: Built binaries in `core/target/release/`
## Troubleshooting
### Package Won't Install
- Check manifest syntax: `yamllint manifest.yaml`
- Verify docker image exists: `tar -tzf docker_images/aarch64.tar | head`
- Check logs on server: `journalctl -u startos -f`
### Service Won't Start
- Check container logs: `docker logs $(docker ps -a | grep atob | awk '{print $1}')`
- Verify entrypoint script exists and is executable
- Check volume mounts in manifest
### Interface Not Accessible
- Verify port mappings in `interfaces` section
- Check that your container is listening on the correct port
- Wait for TOR address generation (can take 2-3 minutes)
## Quick Reference
```bash
# Pack a package
startos pack
# Inspect a package
startos inspect atob.s9pk
# Install (CLI)
startos package.sideload atob.s9pk
# List installed packages
startos package.list
# Uninstall
startos package.uninstall atob
# Check package status
startos package.properties atob
```