# Orama Network Deployment Guide Complete guide for deploying applications and managing databases on Orama Network. ## Table of Contents - [Overview](#overview) - [Authentication](#authentication) - [Deploying Static Sites (React, Vue, etc.)](#deploying-static-sites) - [Deploying Next.js Applications](#deploying-nextjs-applications) - [Deploying Go Backends](#deploying-go-backends) - [Deploying Node.js Backends](#deploying-nodejs-backends) - [Managing SQLite Databases](#managing-sqlite-databases) - [How Domains Work](#how-domains-work) - [Full-Stack Application Example](#full-stack-application-example) - [Managing Deployments](#managing-deployments) - [Troubleshooting](#troubleshooting) --- ## Overview Orama Network provides a decentralized platform for deploying web applications and managing databases. Each deployment: - **Gets a unique domain** automatically (e.g., `myapp.orama.network`) - **Isolated per namespace** - your data and apps are completely separate from others - **Served from IPFS** (static) or **runs as a process** (dynamic apps) - **Fully managed** - automatic health checks, restarts, and logging ### Supported Deployment Types | Type | Description | Use Case | Domain Example | |------|-------------|----------|----------------| | **Static** | HTML/CSS/JS files served from IPFS | React, Vue, Angular, plain HTML | `myapp.orama.network` | | **Next.js** | Next.js with SSR support | Full-stack Next.js apps | `myapp.orama.network` | | **Go** | Compiled Go binaries | REST APIs, microservices | `api.orama.network` | | **Node.js** | Node.js applications | Express APIs, TypeScript backends | `backend.orama.network` | --- ## Authentication Before deploying, authenticate with your wallet: ```bash # Authenticate orama auth login # Check authentication status orama auth whoami ``` Your API key is stored securely and used for all deployment operations. --- ## Deploying Static Sites Deploy static sites built with React, Vue, Angular, or any static site generator. ### React/Vite Example ```bash # 1. Build your React app cd my-react-app npm run build # 2. Deploy the build directory orama deploy static ./dist --name my-react-app --domain repoanalyzer.ai # Output: # 📦 Creating tarball from ./dist... # ☁️ Uploading to Orama Network... # # ✅ Deployment successful! # # Name: my-react-app # Type: static # Status: active # Version: 1 # Content CID: QmXxxx... # # URLs: # • https://my-react-app.orama.network ``` ### What Happens Behind the Scenes 1. **Tarball Creation**: CLI automatically creates a `.tar.gz` from your directory 2. **IPFS Upload**: Files are uploaded to IPFS and pinned across the network 3. **DNS Record**: A DNS record is created pointing `my-react-app.orama.network` to the gateway 4. **Instant Serving**: Your app is immediately accessible via the URL ### Features - ✅ **SPA Routing**: Unknown routes automatically serve `/index.html` (perfect for React Router) - ✅ **Correct Content-Types**: Automatically detects and serves `.html`, `.css`, `.js`, `.json`, `.png`, etc. - ✅ **Caching**: `Cache-Control: public, max-age=3600` headers for optimal performance - ✅ **Zero Downtime Updates**: Use `--update` flag to update without downtime ### Updating a Deployment ```bash # Make changes to your app # Rebuild npm run build # Update deployment orama deploy static ./dist --name my-react-app --update # Version increments automatically (1 → 2) ``` --- ## Deploying Next.js Applications Deploy Next.js apps with full SSR (Server-Side Rendering) support. ### Next.js with SSR ```bash # 1. Build your Next.js app cd my-nextjs-app npm run build # 2. Deploy with SSR enabled orama deploy nextjs . --name my-nextjs --ssr # Output: # 📦 Creating tarball from . # ☁️ Uploading to Orama Network... # # ✅ Deployment successful! # # Name: my-nextjs # Type: nextjs # Status: active # Version: 1 # Port: 10100 # # URLs: # • https://my-nextjs.orama.network # # ⚠️ Note: SSR deployment may take a minute to start. Check status with: orama deployments get my-nextjs ``` ### What Happens Behind the Scenes 1. **Tarball Upload**: Your `.next` build directory, `package.json`, and `public` are uploaded 2. **Home Node Assignment**: A node is chosen to host your app based on capacity 3. **Port Allocation**: A unique port (10100-19999) is assigned 4. **Systemd Service**: A systemd service is created to run `node server.js` 5. **Health Checks**: Gateway monitors your app every 30 seconds 6. **Reverse Proxy**: Gateway proxies requests from your domain to the local port ### Static Next.js Export (No SSR) If you export Next.js to static HTML: ```bash # next.config.js module.exports = { output: 'export' } # Build and deploy as static npm run build orama deploy static ./out --name my-nextjs-static ``` --- ## Deploying Go Backends Deploy compiled Go binaries for high-performance APIs. ### Go REST API Example ```bash # 1. Build your Go binary for Linux (if on Mac/Windows) cd my-go-api GOOS=linux GOARCH=amd64 go build -o api main.go # 2. Deploy the binary orama deploy go ./api --name my-api # Output: # 📦 Creating tarball from ./api... # ☁️ Uploading to Orama Network... # # ✅ Deployment successful! # # Name: my-api # Type: go # Status: active # Version: 1 # Port: 10101 # # URLs: # • https://my-api.orama.network ``` ### Example Go API Code ```go // main.go package main import ( "encoding/json" "log" "net/http" "os" ) func main() { port := os.Getenv("PORT") if port == "" { port = "8080" } http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(map[string]string{"status": "healthy"}) }) http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) { users := []map[string]interface{}{ {"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}, } json.NewEncoder(w).Encode(users) }) log.Printf("Starting server on port %s", port) log.Fatal(http.ListenAndServe(":"+port, nil)) } ``` ### Important Notes - **Environment Variables**: The `PORT` environment variable is automatically set to your allocated port - **Health Endpoint**: Recommended to implement `/health` for monitoring - **Binary Requirements**: Must be Linux-compatible (GOOS=linux GOARCH=amd64) - **Systemd Managed**: Runs as a systemd service with auto-restart on failure --- ## Deploying Node.js Backends Deploy Node.js/Express/TypeScript backends. ### Express API Example ```bash # 1. Build your Node.js app (if using TypeScript) cd my-node-api npm run build # 2. Deploy (must include node_modules or use a bundler) orama deploy nodejs ./dist --name my-node-api # Output: # 📦 Creating tarball from ./dist... # ☁️ Uploading to Orama Network... # # ✅ Deployment successful! # # Name: my-node-api # Type: nodejs # Status: active # Version: 1 # Port: 10102 # # URLs: # • https://my-node-api.orama.network ``` ### Example Node.js API ```javascript // server.js const express = require('express'); const app = express(); const port = process.env.PORT || 8080; app.get('/health', (req, res) => { res.json({ status: 'healthy' }); }); app.get('/api/data', (req, res) => { res.json({ message: 'Hello from Orama Network!' }); }); app.listen(port, () => { console.log(`Server running on port ${port}`); }); ``` --- ## Managing SQLite Databases Each namespace gets its own isolated SQLite databases. ### Creating a Database ```bash # Create a new database orama db create my-database # Output: # ✅ Database created: my-database # Home Node: node-abc123 # File Path: /home/debros/.orama/data/sqlite/your-namespace/my-database.db ``` ### Executing Queries ```bash # Create a table orama db query my-database "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)" # Insert data orama db query my-database "INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')" # Query data orama db query my-database "SELECT * FROM users" # Output: # 📊 Query Result # Rows: 1 # # id | name | email # ----------------+-----------------+------------------------- # 1 | Alice | alice@example.com ``` ### Listing Databases ```bash orama db list # Output: # NAME SIZE HOME NODE CREATED # my-database 12.3 KB node-abc123 2024-01-22 10:30 # prod-database 1.2 MB node-abc123 2024-01-20 09:15 # # Total: 2 ``` ### Backing Up to IPFS ```bash # Create a backup orama db backup my-database # Output: # ✅ Backup created # CID: QmYxxx... # Size: 12.3 KB # List backups orama db backups my-database # Output: # VERSION CID SIZE DATE # 1 QmYxxx... 12.3 KB 2024-01-22 10:45 # 2 QmZxxx... 15.1 KB 2024-01-22 14:20 ``` ### Database Features - ✅ **WAL Mode**: Write-Ahead Logging for better concurrency - ✅ **Namespace Isolation**: Complete separation between namespaces - ✅ **Automatic Backups**: Scheduled backups to IPFS every 6 hours - ✅ **ACID Transactions**: Full SQLite transactional support - ✅ **Concurrent Reads**: Multiple readers can query simultaneously --- ## How Domains Work ### Domain Assignment When you deploy an application, it automatically gets a domain: ``` Format: {deployment-name}.orama.network Example: my-react-app.orama.network ``` ### Node-Specific Domains (Optional) For direct access to a specific node: ``` Format: {deployment-name}.{node-id}.orama.network Example: my-react-app.node-7prvNa.orama.network ``` ### DNS Resolution Flow 1. **Client**: Browser requests `my-react-app.orama.network` 2. **DNS**: CoreDNS server queries RQLite for DNS record 3. **Record**: Returns IP address of a gateway node 4. **Gateway**: Receives request with `Host: my-react-app.orama.network` header 5. **Routing**: Domain routing middleware looks up deployment by domain 6. **Response**: - **Static**: Serves content from IPFS - **Dynamic**: Reverse proxies to the app's local port ### Custom Domains (Future Feature) Support for custom domains (e.g., `www.myapp.com`) with TXT record verification. --- ## Full-Stack Application Example Deploy a complete full-stack application with React frontend, Go backend, and SQLite database. ### Architecture ``` ┌─────────────────────────────────────────────┐ │ React Frontend (Static) │ │ Domain: myapp.orama.network │ │ Deployed to IPFS │ └─────────────────┬───────────────────────────┘ │ │ API Calls ▼ ┌─────────────────────────────────────────────┐ │ Go Backend (Dynamic) │ │ Domain: myapp-api.orama.network │ │ Port: 10100 │ │ Systemd Service │ └─────────────────┬───────────────────────────┘ │ │ SQL Queries ▼ ┌─────────────────────────────────────────────┐ │ SQLite Database │ │ Name: myapp-db │ │ File: ~/.orama/data/sqlite/ns/myapp-db.db│ └─────────────────────────────────────────────┘ ``` ### Step 1: Create the Database ```bash # Create database orama db create myapp-db # Create schema orama db query myapp-db "CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )" # Insert test data orama db query myapp-db "INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')" ``` ### Step 2: Deploy Go Backend **Backend Code** (`main.go`): ```go package main import ( "database/sql" "encoding/json" "log" "net/http" "os" _ "github.com/mattn/go-sqlite3" ) type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` CreatedAt string `json:"created_at"` } var db *sql.DB func main() { // DATABASE_NAME env var is automatically set by Orama dbPath := os.Getenv("DATABASE_PATH") if dbPath == "" { dbPath = "/home/debros/.orama/data/sqlite/" + os.Getenv("NAMESPACE") + "/myapp-db.db" } var err error db, err = sql.Open("sqlite3", dbPath) if err != nil { log.Fatal(err) } defer db.Close() port := os.Getenv("PORT") if port == "" { port = "8080" } // CORS middleware http.HandleFunc("/", corsMiddleware(routes)) log.Printf("Starting server on port %s", port) log.Fatal(http.ListenAndServe(":"+port, nil)) } func routes(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/health": json.NewEncoder(w).Encode(map[string]string{"status": "healthy"}) case "/api/users": if r.Method == "GET" { getUsers(w, r) } else if r.Method == "POST" { createUser(w, r) } default: http.NotFound(w, r) } } func getUsers(w http.ResponseWriter, r *http.Request) { rows, err := db.Query("SELECT id, name, email, created_at FROM users ORDER BY id") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() var users []User for rows.Next() { var u User rows.Scan(&u.ID, &u.Name, &u.Email, &u.CreatedAt) users = append(users, u) } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(users) } func createUser(w http.ResponseWriter, r *http.Request) { var u User if err := json.NewDecoder(r.Body).Decode(&u); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } result, err := db.Exec("INSERT INTO users (name, email) VALUES (?, ?)", u.Name, u.Email) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } id, _ := result.LastInsertId() u.ID = int(id) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(u) } func corsMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return } next(w, r) } } ``` **Deploy Backend**: ```bash # Build for Linux GOOS=linux GOARCH=amd64 go build -o api main.go # Deploy orama deploy go ./api --name myapp-api ``` ### Step 3: Deploy React Frontend **Frontend Code** (`src/App.jsx`): ```jsx import { useEffect, useState } from 'react'; function App() { const [users, setUsers] = useState([]); const [name, setName] = useState(''); const [email, setEmail] = useState(''); const API_URL = 'https://myapp-api.orama.network'; useEffect(() => { fetchUsers(); }, []); const fetchUsers = async () => { const response = await fetch(`${API_URL}/api/users`); const data = await response.json(); setUsers(data); }; const addUser = async (e) => { e.preventDefault(); await fetch(`${API_URL}/api/users`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, email }), }); setName(''); setEmail(''); fetchUsers(); }; return (