Skip to content

Deploying Dropserver

Introduction

Dropserver is an open-source application platform designed to host personal web services for individuals, families, small teams, and clubs. Unlike traditional platforms that scale applications to serve thousands of users, Dropserver focuses on running multiple small-scale applications for small groups of trusted users. Built in Go with Deno-powered sandboxing, Dropserver provides a secure, efficient environment for self-hosted web applications.

Dropserver is designed to be:

  • Personal-Scale: Optimized for applications serving you, your family, or small teamsβ€”not thousands of users
  • Multi-App Platform: Run dozens of different applications on a single instance
  • Sandboxed & Secure: Each app runs in isolated Deno sandboxes with explicit permission controls
  • User-Friendly: One-click app installation with no technical configuration required
  • Privacy-First: Your data stays under your control on your infrastructure
  • Resource-Efficient: Apps only consume resources when actively used
  • Portable: Export apps and data to move between Dropserver instances

Key features include:

  • Appspaces: Isolated instances of applications with their own data and users
  • User Management: Built-in authentication system with avatars and access controls
  • Deno Sandboxing: TypeScript/JavaScript applications run in secure Deno sandboxes
  • Permission System: Granular control over filesystem, network, and API access
  • Data Migration: Built-in hooks for upgrading app data schemas
  • Static Asset Serving: Efficient delivery of frontend resources
  • Public and Private Routes: Mix authenticated and public-facing endpoints
  • Development Tools: ds-dev provides local development environment for building apps

This guide walks you through deploying Dropserver on Klutch.sh using Docker, including configuration for subdomain routing, persistent storage, Deno installation, and production-ready deployment practices.

Why Deploy Dropserver on Klutch.sh?

Klutch.sh provides an excellent platform for hosting Dropserver with several advantages:

  • Automatic Docker Detection: Klutch.sh detects your Dockerfile and builds containers automatically
  • Subdomain Support: Perfect for Dropserver’s subdomain-based appspace routing
  • Built-in HTTPS: Automatic SSL certificates for main domain and all subdomains
  • Persistent Volumes: Reliable storage for appspace data, user information, and uploads
  • Environment Management: Securely configure domains, ports, and application settings
  • Always Available: 24/7 uptime for your personal web services
  • Scalable Resources: Adjust CPU/RAM as your appspace collection grows
  • Simple Deployment: Push to GitHub and deployβ€”no complex infrastructure management

Prerequisites

Before deploying Dropserver to Klutch.sh, ensure you have:

  • A Klutch.sh account (free to get started)
  • A GitHub account for repository hosting
  • Docker installed locally for testing (recommended)
  • A domain with wildcard subdomain support (*.yourdomain.com)
  • Basic understanding of Docker, web applications, and DNS configuration
  • Familiarity with TypeScript or JavaScript (for building custom apps)

Understanding Dropserver Architecture

Dropserver operates on a unique multi-tenant application platform model:

Core Components

ds-host: The main Dropserver executable

  • Written in Go for performance and reliability
  • Serves administrator UI, user authentication, and appspace requests
  • Manages application lifecycle, user permissions, and data storage
  • Handles TLS termination and subdomain routing
  • Coordinates Deno sandboxes for app execution

Deno Runtime: Sandboxed execution environment

  • Each app runs in isolated Deno sandbox
  • TypeScript and JavaScript support
  • Explicit permission model (filesystem, network, env access)
  • Prevents apps from interfering with each other or the host system
  • Lightweight and fast startup for on-demand execution

Appspaces: Isolated application instances

  • Each appspace is a running instance of an installed application
  • Has its own subdomain (e.g., leftovers.example.com)
  • Maintains separate data storage and user access lists
  • Multiple appspaces can run from the same app package
  • Only consumes resources when actively handling requests

Application Model: How apps are structured

  • Apps are TypeScript/JavaScript packages with a manifest
  • Define routes (public and private), data schema, and permissions
  • Access Dropserver APIs for user management, file storage, etc.
  • Can be exported/imported between Dropserver instances
  • Version controlled with migration hooks for data schema changes

Data Flow

  1. User navigates to subdomain (e.g., shopping.example.com)
  2. Dropserver routes request to corresponding appspace
  3. User authentication checked (if private route)
  4. Appspace Deno sandbox initialized (if not already running)
  5. App code handles request and generates response
  6. Static assets served efficiently without sandbox overhead
  7. Sandbox idles out after period of inactivity

Port and Domain Requirements

  • HTTP/HTTPS: Port 3003 (customizable) for all traffic
  • Subdomain Routing: Requires wildcard DNS (*.yourdomain.com)
  • Admin Subdomain: Typically dropid.yourdomain.com for management
  • Appspace Subdomains: Each appspace gets unique subdomain
  • TLS Required: Dropserver requires HTTPS in production

Installation and Setup

Step 1: Create Your Project Repository

Create a new directory for your Dropserver deployment:

Terminal window
mkdir dropserver-klutch
cd dropserver-klutch
git init

Step 2: Create the Dockerfile

Create a Dockerfile in your project root. Klutch.sh automatically detects and builds from this file:

# Build stage - Download and prepare Dropserver
FROM debian:bookworm-slim AS downloader
# Install dependencies for downloading and extracting
RUN apt-get update && apt-get install -y \
curl \
ca-certificates \
unzip \
&& rm -rf /var/lib/apt/lists/*
# Download latest Dropserver release (x86-64)
WORKDIR /tmp
RUN curl -L https://github.com/teleclimber/Dropserver/releases/download/v0.14.4/ds-host-v0.14.4-x86-64.zip -o dropserver.zip && \
unzip dropserver.zip && \
chmod +x ds-host
# Runtime stage - Minimal image with Deno and Dropserver
FROM debian:bookworm-slim
# Install runtime dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
unzip \
&& rm -rf /var/lib/apt/lists/*
# Install Deno (required for app sandboxing)
RUN curl -fsSL https://deno.land/install.sh | sh
ENV DENO_INSTALL="/root/.deno"
ENV PATH="$DENO_INSTALL/bin:$PATH"
# Copy Dropserver binary from build stage
COPY --from=downloader /tmp/ds-host /usr/local/bin/ds-host
# Create directories for data and sockets
RUN mkdir -p /srv/dropserver /var/run/dropserver && \
chmod 755 /srv/dropserver /var/run/dropserver
# Create config directory
RUN mkdir -p /etc/dropserver
# Copy configuration file (we'll create this next)
COPY config.json /etc/dropserver/config.json
WORKDIR /srv/dropserver
# Expose Dropserver port
EXPOSE 3003
# Health check
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -f http://localhost:3003/health || exit 1
# Start Dropserver
CMD ["ds-host", "-config=/etc/dropserver/config.json"]

Dockerfile Explanation:

  • Multi-stage build: Downloads Dropserver in separate stage for smaller final image
  • Deno installation: Required for app sandboxing
  • Data directories: /srv/dropserver for persistent data, /var/run/dropserver for sockets
  • Port 3003: Default Dropserver HTTP port (customizable)
  • Health check: Monitors server availability

Step 3: Create Configuration File

Create config.json in your project root for Dropserver configuration:

{
"data-dir": "/srv/dropserver",
"server": {
"http-port": 3003,
"no-tls": true
},
"external-access": {
"scheme": "https",
"domain": "example.com",
"subdomain": "dropid"
},
"sandbox": {
"sockets-dir": "/var/run/dropserver",
"use-bubblewrap": false,
"use-cgroups": false,
"memory-high-mb": 512
}
}

Configuration Explanation:

  • data-dir: Where Dropserver stores appspace data, user info, and uploads
  • server.http-port: Internal port Dropserver listens on
  • server.no-tls: Set to true since Klutch.sh handles TLS termination
  • external-access.scheme: Always https in production (Klutch.sh provides SSL)
  • external-access.domain: Your custom domain (replace example.com)
  • external-access.subdomain: Subdomain for admin interface (typically dropid)
  • sandbox.sockets-dir: Unix socket directory for sandbox communication
  • sandbox.use-cgroups: Set to false (cgroups require systemd delegation)
  • sandbox.memory-high-mb: Memory limit for all sandboxes combined

Important: Replace example.com with your actual domain before deployment.

Step 4: Create Environment Variables Template

Create .env.example file documenting configuration options:

# Dropserver Environment Configuration
# Domain Configuration
DROPSERVER_DOMAIN=example.com
DROPSERVER_SUBDOMAIN=dropid
# Server Configuration
DROPSERVER_PORT=3003
DROPSERVER_DATA_DIR=/srv/dropserver
DROPSERVER_SOCKETS_DIR=/var/run/dropserver
# Sandbox Configuration
DROPSERVER_MEMORY_LIMIT_MB=512
DROPSERVER_USE_CGROUPS=false
# External Access (Klutch.sh handles TLS)
DROPSERVER_SCHEME=https
DROPSERVER_NO_TLS=true

Step 5: Create .dockerignore File

Create .dockerignore to exclude unnecessary files from the build:

.git
.github
.gitignore
.env
.env.local
*.md
README.md
node_modules
.DS_Store

Step 6: Add Documentation Files

Create README.md with deployment instructions:

# Dropserver on Klutch.sh
Personal web services application platform deployed on Klutch.sh.
## Features
- Sandboxed multi-app hosting
- Built-in user management
- Subdomain-based appspace routing
- Deno-powered TypeScript/JavaScript apps
- Data export and migration support
- One-click app installation
## Deployment
This Dropserver instance is deployed on Klutch.sh with automatic Docker builds.
### Prerequisites
1. Domain with wildcard DNS configured (*.yourdomain.com)
2. DNS A/AAAA records pointing to Klutch.sh infrastructure
3. Klutch.sh account with custom domain configured
### Configuration
Update `config.json` before deployment:
- Set `external-access.domain` to your domain
- Choose `external-access.subdomain` for admin interface
- Adjust `sandbox.memory-high-mb` based on expected app usage
### Persistent Storage
Attach a persistent volume in Klutch.sh dashboard:
- **Mount Path**: `/srv/dropserver`
- **Size**: 10GB minimum (scale based on number of appspaces)
### Initial Setup
1. Deploy to Klutch.sh
2. Look for `setup_key_reveal=` in logs
3. Use the secret link to create admin account
4. Access admin interface at https://dropid.yourdomain.com
5. Create your dropid (user identity)
6. Install apps from URL or manual upload
7. Create appspaces for installed apps
## Building Custom Apps
See <a href="https://dropserver.org/docs/build-dropserver-app-tutorial" target="_blank" rel="noopener noreferrer">Dropserver app tutorial</a> for building your own apps.
## License
Apache License Version 2.0 (Dropserver) - See <a href="https://github.com/teleclimber/Dropserver" target="_blank" rel="noopener noreferrer">original repository</a> for details

Step 7: Initialize Git and Push to GitHub

Terminal window
# Initialize git repository
git init
# Add all files
git add Dockerfile config.json .dockerignore .env.example README.md
# Commit files
git commit -m "Initial Dropserver deployment configuration"
# Add GitHub remote (replace with your repository URL)
git remote add origin https://github.com/yourusername/dropserver-klutch.git
# Push to GitHub
git branch -M main
git push -u origin main

Deploying to Klutch.sh

Step 1: Configure Domain DNS

Before deploying, configure your domain’s DNS:

  1. Add an A record for your root domain pointing to Klutch.sh IP
  2. Add a wildcard A record (*) pointing to the same IP
  3. Repeat for AAAA records if using IPv6
  4. Wait for DNS propagation (typically 5-15 minutes)

Example DNS Configuration:

Type Name Value
A @ <klutch-ip>
A * <klutch-ip>
AAAA @ <klutch-ipv6>
AAAA * <klutch-ipv6>

Step 2: Create New App on Klutch.sh

  1. Navigate to the Klutch.sh dashboard
  2. Click **Create New App** or **New Deployment**
  3. Select **GitHub** as your source
  4. Authenticate with GitHub if not already connected
  5. Choose your Dropserver repository from the list
  6. Select the `main` branch for deployment

Step 3: Configure Application Settings

  1. **App Name**: Choose a unique name (e.g., `dropserver-platform`)
  2. **Traffic Type**: Select **HTTP** traffic
  3. **Internal Port**: Set to `3003` (Dropserver's HTTP port)

Important: Dropserver requires HTTP traffic mode for subdomain routing. The server listens on port 3003 internally.

Step 4: Configure Custom Domain

  1. In app settings, navigate to **Custom Domains**
  2. Add your domain (e.g., `example.com`)
  3. Enable **Wildcard Subdomain** support
  4. Klutch.sh will automatically provision SSL certificates

Step 5: Attach Persistent Volume

  1. Navigate to **Volumes** in app settings
  2. Click **Add Volume** or **Create Volume**
  3. **Mount Path**: `/srv/dropserver`
  4. **Size**: Start with 10GB (increase based on usage)
  5. Click **Save** or **Attach**

Storage Recommendations:

  • Small deployment (1-5 users, 5-10 apps): 10GB
  • Medium deployment (5-20 users, 10-25 apps): 25GB
  • Large deployment (20+ users, 25+ apps): 50GB+

Step 6: Set Environment Variables (Optional)

While configuration is in config.json, you can override settings via environment variables:

DROPSERVER_DOMAIN=yourdomain.com
DROPSERVER_SUBDOMAIN=dropid

Note: The Dockerfile uses the config.json file by default. Environment variables are useful for testing different configurations.

Step 7: Deploy Application

  1. Review all settings in the Klutch.sh dashboard
  2. Click **Deploy** or **Create App**
  3. Klutch.sh will automatically detect the Dockerfile and build your container
  4. Wait for the build to complete (typically 5-8 minutes for first deployment)
  5. Monitor build logs for any errors
  6. Once deployed, your app will be available at `https://dropid.yourdomain.com`

Step 8: Initial Admin Setup

  1. After successful deployment, check application logs in Klutch.sh dashboard
  2. Look for line containing `setup_key_reveal=` followed by a secret URL
  3. Copy the complete URL (e.g., `https://dropid.yourdomain.com/setup?key=...`)
  4. Open the URL in your browser to access the admin registration page
  5. Create your admin account with email and password
  6. Log in with your new admin credentials

Security Note: The setup key is only generated on first run when no admin exists. Save your admin credentials securely.

Step 9: Create Your Dropid

After logging in as admin:

  1. Navigate to **Dropids** section in admin interface
  2. Click **Create New Dropid**
  3. Enter your display name and optionally upload an avatar
  4. Save your dropid (this is your user identity for appspaces)

Step 10: Install Your First App

  1. Navigate to **Apps** section in admin interface
  2. Choose installation method: - **From URL**: Enter app package URL (e.g., from Leftovers or Shopping List) - **Manual Upload**: Upload a `.tar.gz` app package
  3. Dropserver validates and installs the app
  4. Navigate to **Appspaces** to create an instance

Step 11: Create an Appspace

  1. In **Appspaces** section, click **Create New Appspace**
  2. Select the app you installed
  3. Choose a subdomain (e.g., `shopping` becomes `shopping.yourdomain.com`)
  4. Add yourself (your dropid) as a user
  5. Optionally add other dropids for collaboration
  6. Click **Create** to launch the appspace
  7. Access your appspace at `https://your-subdomain.yourdomain.com`

Understanding Appspaces and Applications

What is an Appspace?

An appspace is a running instance of an application with:

  • Unique subdomain: Isolated origin for security
  • Private data storage: Each appspace has its own database/files
  • User list: Control who can access this specific instance
  • Resource isolation: Runs in its own Deno sandbox
  • Independent configuration: Settings separate from other appspaces

Think of appspaces like separate installations of the same app. You might have:

  • shopping.yourdomain.com - Shopping list for your household
  • groceries.yourdomain.com - Shopping list for your extended family
  • leftovers.yourdomain.com - Fridge tracker for your home

All three are instances of the same shopping list app, but with separate data and users.

How Apps Work

Dropserver apps are TypeScript/JavaScript packages with:

App Manifest (app-manifest.json):

{
"name": "Shopping List",
"version": "1.2.0",
"short-description": "Collaborative shopping lists",
"entrypoint": "backend/app.ts",
"schema": 2,
"permissions": {
"files": ["read", "write"],
"env": []
}
}

Backend Code (backend/app.ts):

import { dropserver } from "dropserver-lib";
// Handle HTTP requests
dropserver.handleRoute("/", async (ctx) => {
return new Response("Hello from Dropserver!", {
headers: { "content-type": "text/html" }
});
});
// Private route requiring authentication
dropserver.handleRoute("/api/items", async (ctx) => {
if (!ctx.user) {
return new Response("Unauthorized", { status: 401 });
}
// Access appspace data
const items = await ctx.appspace.readFile("items.json");
return new Response(items, {
headers: { "content-type": "application/json" }
});
});

Frontend Assets: HTML, CSS, JavaScript served statically

App Permissions

Dropserver’s security model requires explicit permissions:

  • Files: Read/write access to appspace data directory
  • Network: Outbound HTTP requests (must specify domains)
  • Environment: Access to environment variables
  • None by default: Apps are sandboxed with zero permissions

Users can review permissions before installing apps.

Getting Started with Dropserver

Managing Users and Dropids

Create Additional Dropids (for other users):

  1. Admin logs into admin interface
  2. Navigate to Dropids section
  3. Click Create New Dropid
  4. Provide display name and email
  5. User receives invitation email
  6. User sets password and accesses their dropid

Invite Users to Appspaces:

  1. Open appspace settings
  2. Click Add User
  3. Select dropid from list
  4. User gets access automatically

Installing Apps from URLs

Many Dropserver apps can be installed via URL:

Leftovers (fridge management):

https://leftovers.olivierforget.net/app/

Shopping List:

https://shoppinglist.olivierforget.net/

Installation steps:

  1. Navigate to Apps in admin interface
  2. Click Install from URL
  3. Paste app URL
  4. Dropserver downloads and validates
  5. App appears in your apps list

Exporting and Importing Appspaces

Export an Appspace:

  1. Open appspace settings
  2. Click Export
  3. Dropserver generates .tar.gz archive
  4. Download contains app code, data, and metadata
  5. Store securely as backup

Import an Appspace:

  1. Navigate to Appspaces section
  2. Click Import
  3. Upload appspace .tar.gz file
  4. Choose subdomain for restored appspace
  5. Dropserver migrates data if app version differs

This allows moving appspaces between Dropserver instances or restoring from backups.

Managing Appspace Data

View Data:

  1. Open appspace settings
  2. Navigate to Files tab
  3. Browse appspace data directory
  4. View/download individual files

Backup Data:

  • Use appspace export (includes code and data)
  • Or manually backup /srv/dropserver volume
  • Schedule regular backups via Klutch.sh

Data Migration:

When updating apps to new versions:

  1. Dropserver detects schema change
  2. Runs migration scripts defined in app
  3. Updates appspace to new schema
  4. Preserves user data through migration

Sample Code Examples

TypeScript - Basic Dropserver App

// backend/app.ts - Simple note-taking app
import { dropserver } from "dropserver-lib";
interface Note {
id: string;
title: string;
content: string;
created: string;
}
// Home page - public route
dropserver.handleRoute("/", async (ctx) => {
if (!ctx.user) {
return new Response(`
<!DOCTYPE html>
<html>
<head><title>Notes App</title></head>
<body>
<h1>Notes App</h1>
<p>Please <a href="/login">log in</a> to access your notes.</p>
</body>
</html>
`, {
headers: { "content-type": "text/html" }
});
}
// Serve notes interface for authenticated users
return new Response(`
<!DOCTYPE html>
<html>
<head>
<title>My Notes</title>
<script src="/static/app.js"></script>
</head>
<body>
<h1>Welcome, ${ctx.user.display_name}!</h1>
<div id="notes-container"></div>
<button onclick="createNote()">New Note</button>
</body>
</html>
`, {
headers: { "content-type": "text/html" }
});
});
// API - Get all notes
dropserver.handleRoute("/api/notes", async (ctx) => {
if (!ctx.user) {
return new Response("Unauthorized", { status: 401 });
}
try {
const notesData = await ctx.appspace.readFile("notes.json");
const notes: Note[] = JSON.parse(notesData);
return new Response(JSON.stringify(notes), {
headers: { "content-type": "application/json" }
});
} catch (error) {
// File doesn't exist yet - return empty array
return new Response("[]", {
headers: { "content-type": "application/json" }
});
}
});
// API - Create new note
dropserver.handleRoute("/api/notes", async (ctx) => {
if (!ctx.user) {
return new Response("Unauthorized", { status: 401 });
}
if (ctx.request.method !== "POST") {
return new Response("Method not allowed", { status: 405 });
}
const body = await ctx.request.json();
const newNote: Note = {
id: crypto.randomUUID(),
title: body.title || "Untitled",
content: body.content || "",
created: new Date().toISOString()
};
// Load existing notes
let notes: Note[] = [];
try {
const notesData = await ctx.appspace.readFile("notes.json");
notes = JSON.parse(notesData);
} catch {
// File doesn't exist - start with empty array
}
// Add new note and save
notes.push(newNote);
await ctx.appspace.writeFile("notes.json", JSON.stringify(notes, null, 2));
return new Response(JSON.stringify(newNote), {
status: 201,
headers: { "content-type": "application/json" }
});
});

JavaScript - App Manifest

{
"name": "Simple Notes",
"version": "1.0.0",
"short-description": "A minimal note-taking app for Dropserver",
"description": "Create and manage personal notes with a clean interface. All notes are stored privately in your appspace.",
"icon": "icon.png",
"authors": [
{
"name": "Your Name",
"email": "you@example.com"
}
],
"code": {
"entrypoint": "backend/app.ts",
"location": "./"
},
"schema": 1,
"migrations": [],
"permissions": {
"files": {
"read": true,
"write": true
},
"routes": {
"public": ["/", "/static/*"],
"authenticated": ["/api/*"]
}
},
"release-date": "2025-12-17"
}

TypeScript - Data Migration Example

// migrations/v2.ts - Migrate from v1 to v2 schema
import { dropserver } from "dropserver-lib";
interface NoteV1 {
id: string;
text: string;
}
interface NoteV2 {
id: string;
title: string;
content: string;
created: string;
}
dropserver.handleMigration(async (ctx) => {
console.log("Migrating notes from v1 to v2...");
// Read old format
const oldNotesData = await ctx.appspace.readFile("notes.json");
const oldNotes: NoteV1[] = JSON.parse(oldNotesData);
// Convert to new format
const newNotes: NoteV2[] = oldNotes.map(note => ({
id: note.id,
title: note.text.slice(0, 50), // First 50 chars as title
content: note.text,
created: "2025-01-01T00:00:00Z" // Default date for old notes
}));
// Save new format
await ctx.appspace.writeFile("notes.json", JSON.stringify(newNotes, null, 2));
console.log(`Migrated ${newNotes.length} notes to v2 schema`);
});

JavaScript - Frontend Integration

// static/app.js - Frontend code for notes app
async function loadNotes() {
try {
const response = await fetch('/api/notes');
const notes = await response.json();
const container = document.getElementById('notes-container');
container.innerHTML = '';
notes.forEach(note => {
const noteEl = document.createElement('div');
noteEl.className = 'note';
noteEl.innerHTML = `
<h3>${escapeHtml(note.title)}</h3>
<p>${escapeHtml(note.content)}</p>
<small>Created: ${new Date(note.created).toLocaleDateString()}</small>
`;
container.appendChild(noteEl);
});
} catch (error) {
console.error('Failed to load notes:', error);
}
}
async function createNote() {
const title = prompt('Note title:');
const content = prompt('Note content:');
if (!title || !content) return;
try {
const response = await fetch('/api/notes', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, content })
});
if (response.ok) {
loadNotes(); // Reload list
} else {
alert('Failed to create note');
}
} catch (error) {
console.error('Failed to create note:', error);
}
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Load notes on page load
document.addEventListener('DOMContentLoaded', loadNotes);

Go - Custom ds-host Configuration

// config-generator.go - Generate Dropserver config programmatically
package main
import (
"encoding/json"
"fmt"
"os"
)
type Config struct {
DataDir string `json:"data-dir"`
Server ServerConfig `json:"server"`
ExternalAccess AccessConfig `json:"external-access"`
Sandbox SandboxConfig `json:"sandbox"`
}
type ServerConfig struct {
HTTPPort int `json:"http-port"`
NoTLS bool `json:"no-tls"`
}
type AccessConfig struct {
Scheme string `json:"scheme"`
Domain string `json:"domain"`
Subdomain string `json:"subdomain"`
}
type SandboxConfig struct {
SocketsDir string `json:"sockets-dir"`
UseBubblewrap bool `json:"use-bubblewrap"`
UseCgroups bool `json:"use-cgroups"`
MemoryHighMB int `json:"memory-high-mb"`
}
func main() {
domain := os.Getenv("DROPSERVER_DOMAIN")
if domain == "" {
domain = "example.com"
}
config := Config{
DataDir: "/srv/dropserver",
Server: ServerConfig{
HTTPPort: 3003,
NoTLS: true,
},
ExternalAccess: AccessConfig{
Scheme: "https",
Domain: domain,
Subdomain: "dropid",
},
Sandbox: SandboxConfig{
SocketsDir: "/var/run/dropserver",
UseBubblewrap: false,
UseCgroups: false,
MemoryHighMB: 512,
},
}
jsonData, err := json.MarshalIndent(config, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "Error generating config: %v\n", err)
os.Exit(1)
}
err = os.WriteFile("/etc/dropserver/config.json", jsonData, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "Error writing config: %v\n", err)
os.Exit(1)
}
fmt.Println("Config generated successfully")
}

Bash - Deployment Helper Script

#!/bin/bash
# deploy-dropserver.sh - Helper script for Dropserver deployment
set -e
DOMAIN="${1:-example.com}"
SUBDOMAIN="${2:-dropid}"
DATA_DIR="/srv/dropserver"
SOCKETS_DIR="/var/run/dropserver"
echo "πŸš€ Dropserver Deployment Helper"
echo "================================"
echo "Domain: $DOMAIN"
echo "Admin subdomain: $SUBDOMAIN.$DOMAIN"
echo ""
# Create directories
echo "πŸ“ Creating directories..."
mkdir -p "$DATA_DIR" "$SOCKETS_DIR"
chmod 755 "$DATA_DIR" "$SOCKETS_DIR"
# Generate config
echo "βš™οΈ Generating configuration..."
cat > config.json <<EOF
{
"data-dir": "$DATA_DIR",
"server": {
"http-port": 3003,
"no-tls": true
},
"external-access": {
"scheme": "https",
"domain": "$DOMAIN",
"subdomain": "$SUBDOMAIN"
},
"sandbox": {
"sockets-dir": "$SOCKETS_DIR",
"use-bubblewrap": false,
"use-cgroups": false,
"memory-high-mb": 512
}
}
EOF
echo "βœ… Configuration generated: config.json"
echo ""
# Check if Deno is installed
if ! command -v deno &> /dev/null; then
echo "⚠️ Warning: Deno not found. Installing..."
curl -fsSL https://deno.land/install.sh | sh
export DENO_INSTALL="$HOME/.deno"
export PATH="$DENO_INSTALL/bin:$PATH"
echo "βœ… Deno installed"
else
echo "βœ… Deno found: $(deno --version | head -1)"
fi
echo ""
echo "πŸŽ‰ Setup complete!"
echo ""
echo "Next steps:"
echo "1. Update config.json with your actual domain"
echo "2. Build Docker image: docker build -t dropserver ."
echo "3. Push to GitHub and deploy on Klutch.sh"
echo "4. Configure DNS (A and * wildcard records)"
echo "5. Attach persistent volume at $DATA_DIR"
echo "6. Access admin at https://$SUBDOMAIN.$DOMAIN"

Advanced Configuration

Custom Subdomain Management

By default, Dropserver uses dropid as the admin subdomain. You can customize this:

In config.json:

{
"external-access": {
"subdomain": "admin",
"domain": "yourdomain.com"
}
}

Access admin at: https://admin.yourdomain.com

Appspace subdomains remain separate (e.g., shopping.yourdomain.com).

Memory and Resource Limits

Control sandbox resource usage:

{
"sandbox": {
"memory-high-mb": 1024,
"use-cgroups": false
}
}

Recommendations:

  • Light usage (1-5 active appspaces): 512MB
  • Medium usage (5-15 active appspaces): 1024MB
  • Heavy usage (15+ active appspaces): 2048MB+

Note: use-cgroups requires systemd delegation, unavailable in standard Docker containers.

TLS Configuration Options

Klutch.sh handles TLS, but for reference, here are Dropserver’s TLS modes:

Behind Reverse Proxy (Klutch.sh default):

{
"server": {
"http-port": 3003,
"no-tls": true
}
}

Direct TLS (if self-hosting):

{
"server": {
"tls-port": 443,
"http-port": 80
},
"manage-certificates": {
"enable": true,
"acme-account-email": "you@example.com"
}
}

Custom Certificates (if self-hosting):

{
"server": {
"tls-port": 443,
"ssl-cert": "/path/to/cert.crt",
"ssl-key": "/path/to/key.key"
}
}

App Permission Management

Review and manage app permissions:

  1. Navigate to Apps in admin interface
  2. Select an app to view details
  3. Review Permissions tab
  4. See exactly what the app can access:
    • File read/write capabilities
    • Network access destinations
    • Environment variable access

Permission Types:

  • Files: read, write, or both
  • Network: List of allowed domains
  • Environment: Specific env variables

Apps cannot access anything not explicitly declared.

Monitoring and Logging

Monitor your Dropserver instance:

View Logs in Klutch.sh:

  1. Navigate to app in Klutch.sh dashboard
  2. Click Logs tab
  3. View real-time application output
  4. Look for:
    • Appspace creation/deletion
    • User authentication events
    • App installation success/failure
    • Sandbox initialization
    • Error messages

Log Levels:

Dropserver logs various events:

  • INFO: Normal operations (appspace created, user logged in)
  • WARN: Non-critical issues (slow sandbox startup)
  • ERROR: Failures requiring attention (app install failed)

Metrics to Monitor:

  • Number of active appspaces
  • Memory usage per sandbox
  • Request latency
  • Failed authentication attempts
  • Disk usage in /srv/dropserver

Production Best Practices

Security Hardening

Domain and Subdomain Security:

  • Always use HTTPS (Klutch.sh provides automatically)
  • Configure wildcard SSL for all subdomains
  • Avoid predictable subdomain names for sensitive appspaces
  • Regularly rotate admin passwords

App Vetting:

  • Review app permissions before installation
  • Only install apps from trusted sources
  • Inspect app code if self-hosting sensitive data
  • Keep apps updated to latest versions

User Management:

  • Use strong passwords for all accounts
  • Limit dropid creation to trusted administrators
  • Regularly audit appspace access lists
  • Remove unused dropids and appspaces

Backup Strategy:

  • Schedule regular volume backups via Klutch.sh
  • Export critical appspaces manually
  • Store backups in separate location
  • Test restore procedures periodically

Performance Optimization

Resource Allocation:

  • Start with conservative memory limits
  • Monitor actual usage via logs
  • Scale up if seeing sandbox initialization delays
  • Consider separating high-traffic appspaces to dedicated instances

Storage Management:

  • Regularly audit /srv/dropserver disk usage
  • Archive or delete unused appspaces
  • Export and remove old appspace versions
  • Plan for growth (appspace data accumulates over time)

App Selection:

  • Prefer lightweight apps for personal use
  • Avoid resource-intensive apps unless necessary
  • Monitor per-app resource consumption
  • Consider app alternatives if performance suffers

Scaling Strategies

Vertical Scaling (same instance, more resources):

  • Increase Dropserver container memory/CPU via Klutch.sh
  • Expand persistent volume size
  • Adjust memory-high-mb in configuration
  • Monitor for resource contention

Horizontal Scaling (multiple instances):

  • Deploy separate Dropserver instances for different purposes
  • One for family, one for work, one for clubs
  • Each instance has independent data and users
  • Use subdomain-per-instance routing (family.yourdomain.com, work.yourdomain.com)

Data Management:

  • Export/import appspaces between instances
  • Migrate high-usage appspaces to dedicated Dropserver
  • Archive inactive appspaces to free resources
  • Plan storage growth based on app types

Backup and Disaster Recovery

Automated Backups:

  1. Configure Klutch.sh volume snapshots (if available)
  2. Or use scheduled export scripts
  3. Store backups in cloud storage (S3, Backblaze, etc.)
  4. Retain multiple backup generations (daily, weekly, monthly)

Manual Export Procedure:

Terminal window
# Export all appspaces (theoretical script)
for appspace in $(list-appspaces); do
export-appspace $appspace /backups/$appspace-$(date +%Y%m%d).tar.gz
done

Restore Procedure:

  1. Deploy fresh Dropserver instance on Klutch.sh
  2. Complete initial admin setup
  3. Install required apps (from URLs or uploads)
  4. Import appspace archives one by one
  5. Verify data integrity and user access

Disaster Recovery Checklist:

  • Admin credentials backed up securely
  • Domain DNS records documented
  • App URLs or packages saved externally
  • Appspace exports stored off-instance
  • Restore procedure tested at least once

Troubleshooting

Issue: Admin Setup Key Not Found

Symptoms: Can’t find setup_key_reveal URL in logs

Solutions:

  1. Check logs carefully:

    • Look for line starting with setup_key_reveal=
    • Check Klutch.sh dashboard Logs tab
    • Search for β€œsetup” in log output
  2. Already have admin:

    • Setup key only appears on first run
    • If admin already exists, log in normally
    • Navigate to admin subdomain (e.g., dropid.yourdomain.com)
  3. Reset database:

    • If needed, delete volume data and redeploy
    • Dropserver will regenerate setup key
    • WARNING: This deletes all data

Issue: Subdomain Not Accessible

Symptoms: Can’t access admin or appspace subdomains

Solutions:

  1. Check DNS configuration:

    Terminal window
    # Verify A record
    dig yourdomain.com
    # Verify wildcard
    dig random-subdomain.yourdomain.com

    Both should point to Klutch.sh IP

  2. DNS propagation:

    • Allow 5-15 minutes after DNS changes
    • Use WhatsMyDNS to check global propagation
    • Try accessing from different networks
  3. Klutch.sh domain configuration:

    • Verify custom domain added in dashboard
    • Ensure wildcard subdomain support enabled
    • Check SSL certificate provisioning status
  4. Configuration mismatch:

    • Verify external-access.domain in config.json
    • Ensure matches actual domain
    • Redeploy after config changes

Issue: App Installation Fails

Symptoms: Error when installing app from URL or upload

Solutions:

  1. Check app URL:

    • Ensure URL is accessible from Dropserver
    • Try accessing URL in browser
    • Verify URL points to valid app package
  2. Manifest validation:

    • App manifest may have errors
    • Check Dropserver logs for validation errors
    • Contact app author if official app
  3. Network permissions:

    • Dropserver needs outbound network access
    • Verify no firewall blocking Dropserver
    • Try manual upload instead of URL
  4. Deno not found:

    • Ensure Deno installed in container
    • Check Dockerfile includes Deno installation
    • Verify deno in PATH

Issue: Appspace Won’t Start

Symptoms: Appspace subdomain returns error or timeout

Solutions:

  1. Check logs:

    • Look for sandbox initialization errors
    • Check for Deno runtime errors
    • Verify app code compatibility
  2. Memory limits:

    • Increase memory-high-mb in config
    • Check if multiple appspaces competing for resources
    • Scale up Dropserver container resources
  3. Deno version compatibility:

    • Some apps require specific Deno versions
    • Update Deno in Dockerfile if needed
    • Check app documentation for requirements
  4. Data corruption:

    • Try exporting and reimporting appspace
    • Check appspace data files for corruption
    • Restore from backup if available

Issue: Slow Appspace Performance

Symptoms: Appspaces take long to respond or load

Solutions:

  1. Resource constraints:

    • Monitor container CPU/memory usage
    • Increase Klutch.sh resource allocation
    • Reduce number of active appspaces
  2. Cold start:

    • First request to idle appspace takes longer
    • Sandbox needs to initialize
    • Subsequent requests should be faster
  3. Storage I/O:

    • Check volume IOPS performance
    • Large appspace data files may be slow
    • Consider SSD-backed volumes
  4. Network latency:

    • Verify Klutch.sh region proximity
    • Check DNS resolution time
    • Test from different networks

Issue: Lost Admin Access

Symptoms: Forgot admin password, can’t log in

Solutions:

  1. Reset not available:

    • Dropserver doesn’t have password reset UI yet
    • Need database-level intervention
  2. Backup and restore:

    • If you have backups, restore to known state
    • Create new admin during setup
  3. Prevention:

    • Store admin credentials in password manager
    • Document recovery procedures
    • Keep multiple admin accounts if critical

Debugging Tools

Check Dropserver Version:

Terminal window
ds-host -version

Verify Deno Installation:

Terminal window
deno --version

Inspect Configuration:

Terminal window
cat /etc/dropserver/config.json

Test Subdomain Resolution:

Terminal window
curl -I https://dropid.yourdomain.com

View Appspace Data:

Terminal window
ls -la /srv/dropserver/appspaces/

Building Custom Dropserver Apps

App Development Workflow

  1. Set up ds-dev locally:

    • Download ds-dev from releases
    • Configure for local development
    • Create new app directory
  2. Create app manifest:

    • Define name, version, permissions
    • Specify entrypoint file
    • Set schema version
  3. Write backend code:

    • Use TypeScript for type safety
    • Implement route handlers
    • Access Dropserver APIs
  4. Add frontend assets:

    • HTML, CSS, JavaScript files
    • Serve via static routes
    • Call backend APIs
  5. Test in ds-dev:

    • Run app locally
    • Test all routes and features
    • Debug with console logs
  6. Package app:

    • Create .tar.gz archive
    • Upload to your Dropserver
    • Or host URL for distribution

App Template Structure

my-app/
β”œβ”€β”€ app-manifest.json # App metadata and config
β”œβ”€β”€ backend/
β”‚ β”œβ”€β”€ app.ts # Main backend entrypoint
β”‚ └── lib/ # Shared backend code
β”œβ”€β”€ frontend/
β”‚ β”œβ”€β”€ index.html # Main UI
β”‚ β”œβ”€β”€ app.js # Frontend logic
β”‚ └── styles.css # Styling
β”œβ”€β”€ migrations/ # Schema migration scripts
β”‚ └── v2.ts
└── icon.png # App icon (square, 256x256+)

Dropserver API Reference

Context Object (ctx):

interface AppContext {
request: Request; // HTTP request
user: User | null; // Authenticated user or null
appspace: {
readFile(path: string): Promise<string>;
writeFile(path: string, data: string): Promise<void>;
deleteFile(path: string): Promise<void>;
listFiles(dir: string): Promise<string[]>;
};
settings: Record<string, any>; // Appspace settings
}

Route Handlers:

dropserver.handleRoute(pattern: string, handler: (ctx) => Response)

Migration Handlers:

dropserver.handleMigration(handler: (ctx) => Promise<void>)

Publishing Your App

Option 1: Self-host app package:

  1. Build .tar.gz archive
  2. Host on your web server
  3. Share URL with users
  4. Users install via URL in their Dropserver

Option 2: GitHub releases:

  1. Create GitHub repository for your app
  2. Tag releases with version numbers
  3. Attach .tar.gz to release
  4. Share GitHub release URL

Option 3: Dropserver app directory (future):

  • Official app directory planned
  • Submit apps for review
  • Users discover and install via UI

Additional Resources


You now have a fully functional Dropserver platform deployed on Klutch.sh! Users can install personal web applications, create isolated appspaces with subdomain routing, invite collaborators, and enjoy the freedom of self-hosted services. Build custom apps with TypeScript, manage everything through the web interface, and maintain complete control over your data and privacy.