Skip to content

Deploying an Algernon App

Introduction

Algernon is a lightweight, fast web server written in Go with built-in support for Lua scripting, making it ideal for serving static files and creating dynamic web applications. Algernon combines the simplicity of a static file server with the power of server-side scripting, providing a modern alternative to traditional web servers.

Algernon is renowned for its:

  • Lightweight: Minimal resource footprint and fast startup times
  • Lua Scripting: Built-in Lua interpreter for server-side scripting
  • Static File Serving: Efficient static file serving with automatic directory listings
  • HTTP/2 Support: Modern HTTP/2 protocol support
  • WebSocket Support: Built-in WebSocket support for real-time applications
  • Template Engine: Built-in template engine for dynamic content
  • Markdown Support: Automatic Markdown rendering
  • Security Features: Built-in security features and HTTPS support
  • Easy Configuration: Simple configuration with command-line options
  • Cross-Platform: Runs on multiple platforms including Linux, macOS, and Windows

Common use cases include static websites, dynamic web applications, API servers, development servers, documentation sites, personal blogs, small web services, and prototyping web applications.

This comprehensive guide walks you through deploying Algernon on Klutch.sh using a Dockerfile, including detailed installation steps, configuration options, sample code, and production-ready best practices for hosting web applications.

Prerequisites

Before you begin, ensure you have the following:

  • A Klutch.sh account
  • A GitHub account with a repository for your Algernon project
  • Docker installed locally for testing (optional but recommended)
  • Basic understanding of web servers, Lua scripting, and web development
  • Optional: Knowledge of Go if you want to customize Algernon

Installation and Setup

Step 1: Create Your Project Directory

First, create a new directory for your Algernon deployment project:

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

Step 2: Create Sample Application Files

Create a basic Algernon application structure. Here’s a minimal example:

public/index.html (static file):

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Algernon App</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h1 {
color: #333;
}
</style>
</head>
<body>
<h1>Welcome to Algernon</h1>
<p>This is a sample Algernon application deployed on Klutch.sh.</p>
<p>Visit <a href="/api/hello">/api/hello</a> for a Lua-powered API endpoint.</p>
</body>
</html>

lua/api.lua (Lua script for API endpoints):

-- API endpoint handler
function handle_api_hello()
return {
status = 200,
headers = {["Content-Type"] = "application/json"},
body = json.encode({
message = "Hello from Algernon!",
timestamp = os.time(),
server = "Algernon on Klutch.sh"
})
}
end
-- Register the route
route("/api/hello", handle_api_hello)

lua/server.lua (main server configuration):

-- Server configuration
server.port = tonumber(os.getenv("PORT")) or 3000
server.host = "0.0.0.0"
-- Enable directory listings
server.dirlist = true
-- Set document root
server.root = "/app/public"
-- Logging
server.log = true

Step 3: Create the Dockerfile

Create a Dockerfile in your project root directory. This will define your Algernon container configuration:

FROM golang:1.21-alpine AS builder
# Install build dependencies
RUN apk add --no-cache \
git \
make
# Set working directory
WORKDIR /build
# Install Algernon
RUN go install github.com/xyproto/algernon@latest
# Production stage
FROM alpine:latest
# Install runtime dependencies
RUN apk add --no-cache \
ca-certificates \
lua5.3 \
curl
# Copy Algernon binary from builder
COPY --from=builder /go/bin/algernon /usr/local/bin/algernon
# Create app directory
WORKDIR /app
# Copy application files
COPY public ./public
COPY lua ./lua
# Create directories for persistent data
RUN mkdir -p /var/lib/algernon/data \
/var/lib/algernon/logs && \
chmod -R 755 /var/lib/algernon
# Expose port
EXPOSE 3000
# Set environment variables
ENV PORT=3000
ENV ALGERNON_DIR=/app
ENV ALGERNON_PORT=3000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD curl -f http://localhost:3000/ || exit 1
# Start Algernon
CMD ["algernon", "--dir", "/app/public", "--lua", "/app/lua", "--port", "3000", "--addr", "0.0.0.0"]

Note: This Dockerfile uses a multi-stage build to create an optimized production image. Algernon runs on port 3000 by default, which will be your internal port in Klutch.sh. The application serves files from /app/public and executes Lua scripts from /app/lua.

Step 4: Create Configuration Files

Create a configuration file for Algernon:

algernon.conf (optional configuration file):

# Algernon Configuration
port=3000
addr=0.0.0.0
dir=/app/public
lua=/app/lua
log=true
dirlist=true

Step 5: Create Environment Configuration Template

Create a .env.example file with required environment variables:

# Server Configuration
PORT=3000
ALGERNON_DIR=/app
ALGERNON_PORT=3000
# Application Configuration
ALGERNON_HOST=0.0.0.0
ALGERNON_LOG=true
ALGERNON_DIRLIST=true
# Storage Paths
ALGERNON_DATA_DIR=/var/lib/algernon/data
ALGERNON_LOGS_DIR=/var/lib/algernon/logs
# Timezone
TZ=UTC

Step 6: Create .dockerignore File

Create a .dockerignore file to exclude unnecessary files from the Docker build:

.git
.gitignore
.dockerignore
.env
.env.local
*.md
docker-compose.yml
docker-compose.*.yml
Dockerfile
*.log

Step 7: Test Locally (Optional)

Before deploying to Klutch.sh, you can test your Algernon setup locally:

Terminal window
# Build the Docker image
docker build -t my-algernon .
# Run the container
docker run -d \
--name algernon-test \
-p 3000:3000 \
-e PORT=3000 \
my-algernon
# Check if the application is running
curl http://localhost:3000/
curl http://localhost:3000/api/hello

Note: For local development, you can use Docker Compose to run Algernon with additional services if needed. Docker Compose is only for local development; Klutch.sh does not support Docker Compose for deployment.

Step 8: Push to GitHub

Commit your Algernon project files to your GitHub repository:

Terminal window
git add .
git commit -m "Initial Algernon Docker setup for Klutch.sh"
git branch -M main
git remote add origin https://github.com/yourusername/algernon-klutch.git
git push -u origin main

Deploying to Klutch.sh

Now that your Algernon project is ready and pushed to GitHub, follow these steps to deploy it on Klutch.sh with persistent storage.

Deployment Steps

    1. Log in to Klutch.sh

      Navigate to klutch.sh/app and sign in to your account.

    2. Create a New Project

      Go to Create Project and give your project a meaningful name (e.g., “Algernon Web Server”).

    3. Create a New App

      Navigate to Create App and configure the following settings:

    4. Select Your Repository

      • Choose GitHub as your Git source
      • Select the repository containing your Dockerfile
      • Choose the branch you want to deploy (usually main or master)

      Klutch.sh will automatically detect the Dockerfile in your repository root and use it for deployment.

    5. Configure Traffic Type

      • Traffic Type: Select HTTP (Algernon is a web server)
      • Internal Port: Set to 3000 (the port your Algernon container listens on, as defined in your Dockerfile)
    6. Set Environment Variables

      Add the following environment variables for your Algernon configuration:

      Server Configuration:

      • PORT: Set to 3000 (matches the internal port)
      • ALGERNON_DIR: Set to /app
      • ALGERNON_PORT: Set to 3000
      • ALGERNON_HOST: Set to 0.0.0.0

      Application Configuration:

      • ALGERNON_LOG: Set to true to enable logging
      • ALGERNON_DIRLIST: Set to true to enable directory listings (optional)

      Storage Paths:

      • ALGERNON_DATA_DIR: Set to /var/lib/algernon/data
      • ALGERNON_LOGS_DIR: Set to /var/lib/algernon/logs

      Timezone:

      • TZ: Your timezone (e.g., UTC or America/New_York)
    7. Attach Persistent Volumes

      Algernon may require persistent storage for data and logs:

      Data Volume (Optional):

      • Mount Path: /var/lib/algernon/data
      • Size: Start with 5GB minimum (10GB+ recommended for production with user uploads)

      This volume stores:

      • User-uploaded files
      • Application data
      • Persistent state

      Logs Volume (Optional):

      • Mount Path: /var/lib/algernon/logs
      • Size: 5GB (for application logs)

      Note: For simple static sites, persistent volumes may not be necessary. Add volumes if you need to persist user data or logs across deployments.

    8. Configure Additional Settings

      • Region: Select the region closest to your users for optimal performance
      • Compute Resources: Algernon is lightweight; allocate at least:
        • CPU: 1 core is sufficient (2+ cores recommended for production)
        • Memory: 512MB minimum (1GB+ recommended for production workloads)
      • Instances: Start with 1 instance (you can scale horizontally later if needed)
    9. Deploy Your Application

      Click “Create” to start the deployment. Klutch.sh will:

      • Automatically detect your Dockerfile in the repository root
      • Build the Docker image
      • Attach the persistent volume(s) if configured
      • Start your Algernon container
      • Assign a URL for external access

      Note: The first deployment may take a few minutes as it builds the Docker image and installs dependencies.

    10. Access Your Application

      Once deployment is complete, you’ll receive a URL like example-app.klutch.sh. Visit this URL to access your Algernon application.


Sample Code: Getting Started with Algernon

Here are some examples to help you build applications with Algernon:

Example 1: Basic Lua API Endpoint

lua/api/status.lua:

-- Status endpoint
function handle_status()
return {
status = 200,
headers = {["Content-Type"] = "application/json"},
body = json.encode({
status = "ok",
server = "Algernon",
version = "1.0",
timestamp = os.time()
})
}
end
route("/api/status", handle_status)

Example 2: Dynamic Content with Templates

lua/pages/about.lua:

-- About page with template
function handle_about()
local template = [[
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
<p>{{content}}</p>
<p>Server time: {{time}}</p>
</body>
</html>
]]
local data = {
title = "About Us",
content = "This is a sample about page.",
time = os.date("%Y-%m-%d %H:%M:%S")
}
local html = template:gsub("{{(%w+)}}", function(key)
return tostring(data[key] or "")
end)
return {
status = 200,
headers = {["Content-Type"] = "text/html"},
body = html
}
end
route("/about", handle_about)

Example 3: Form Handling

lua/api/submit.lua:

-- Form submission handler
function handle_submit()
local method = request.method
if method == "POST" then
-- Parse form data
local name = request.form.name or ""
local email = request.form.email or ""
-- Process the form data
-- (In a real application, you might save this to a database)
return {
status = 200,
headers = {["Content-Type"] = "application/json"},
body = json.encode({
success = true,
message = "Form submitted successfully",
data = {
name = name,
email = email
}
})
}
else
return {
status = 405,
headers = {["Content-Type"] = "text/plain"},
body = "Method not allowed"
}
end
end
route("/api/submit", handle_submit)

Example 4: File Upload Handler

lua/api/upload.lua:

-- File upload handler
function handle_upload()
if request.method == "POST" then
local file = request.files.upload
if file then
-- Save file to data directory
local filename = file.filename
local filepath = "/var/lib/algernon/data/" .. filename
-- Write file (simplified example)
-- In production, add proper error handling and validation
return {
status = 200,
headers = {["Content-Type"] = "application/json"},
body = json.encode({
success = true,
message = "File uploaded successfully",
filename = filename
})
}
else
return {
status = 400,
headers = {["Content-Type"] = "application/json"},
body = json.encode({
success = false,
message = "No file provided"
})
}
end
else
return {
status = 405,
headers = {["Content-Type"] = "text/plain"},
body = "Method not allowed"
}
end
end
route("/api/upload", handle_upload)

Example 5: JavaScript Client Example

// Frontend JavaScript example for Algernon API
async function getStatus() {
try {
const response = await fetch('https://example-app.klutch.sh/api/status', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Status:', data);
return data;
} catch (error) {
console.error('Error fetching status:', error);
throw error;
}
}
async function submitForm(formData) {
try {
const response = await fetch('https://example-app.klutch.sh/api/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
},
body: new URLSearchParams(formData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Form submitted:', data);
return data;
} catch (error) {
console.error('Error submitting form:', error);
throw error;
}
}
// Example usage
getStatus().then(status => {
console.log('Server status:', status.status);
});
submitForm({
name: 'John Doe',
email: 'john@example.com'
}).then(result => {
console.log('Submission result:', result);
});

Production Best Practices

Security Recommendations

  • Enable HTTPS: Always use HTTPS in production (Klutch.sh provides TLS certificates)
  • Input Validation: Always validate and sanitize user input in Lua scripts
  • File Upload Security: Implement proper file type validation and size limits for uploads
  • Error Handling: Implement proper error handling without exposing sensitive information
  • Rate Limiting: Consider implementing rate limiting for API endpoints
  • Access Control: Implement proper access control for sensitive endpoints
  • Regular Updates: Keep Algernon and dependencies updated with security patches
  • Logging: Enable logging for security monitoring
  • Environment Variables: Store sensitive configuration as environment variables

Performance Optimization

  • Static File Caching: Configure appropriate caching headers for static files
  • CDN Integration: Consider using a CDN for static assets
  • Lua Script Optimization: Optimize Lua scripts for performance
  • Resource Monitoring: Monitor CPU and memory usage
  • Connection Pooling: If using databases, configure appropriate connection pools
  • Compression: Enable gzip compression for responses

Monitoring and Maintenance

Monitor your Algernon application for:

  • Application Logs: Check logs in Klutch.sh dashboard for errors
  • Response Times: Track API response times
  • Error Rates: Monitor 4xx and 5xx error rates
  • Resource Usage: Track CPU and memory usage in Klutch.sh dashboard
  • Storage Usage: Monitor persistent volume usage if configured

Regular maintenance tasks:

  • Backup Data: Regularly backup data from persistent volumes if configured
  • Update Dependencies: Keep Go and Algernon updated
  • Review Logs: Review application and error logs regularly
  • Security Audits: Perform regular security audits
  • Code Review: Review and optimize Lua scripts

Troubleshooting

Application Not Loading

  • Verify the app’s Traffic Type is HTTP
  • Check that the internal port is set to 3000 and matches your Dockerfile
  • Review build and runtime logs in the Klutch.sh dashboard
  • Ensure Algernon starts correctly (check the CMD in Dockerfile)
  • Verify all required files are in the correct directories

Lua Scripts Not Executing

  • Verify Lua scripts are in the /app/lua directory
  • Check Lua script syntax for errors
  • Review application logs for Lua execution errors
  • Ensure route handlers are properly defined
  • Verify file permissions on Lua scripts

Static Files Not Serving

  • Verify static files are in the /app/public directory
  • Check file permissions on static files
  • Review Algernon configuration for document root
  • Verify directory listing settings if needed

Performance Issues

  • Review resource allocation in Klutch.sh (CPU and memory)
  • Optimize Lua scripts for better performance
  • Check for inefficient file operations
  • Monitor database connections if using databases
  • Review and optimize static file serving

Data Not Persisting

  • Ensure persistent volumes are correctly mounted
  • Check file permissions on persistent volumes
  • Verify the application is writing to the correct directories
  • Ensure sufficient disk space in persistent volumes


Conclusion

Deploying Algernon to Klutch.sh with a Dockerfile provides a lightweight, fast web server with Lua scripting capabilities, persistent storage options, and production-ready configuration. By following this guide, you’ve set up a high-performance Algernon instance with proper configuration, security settings, and the ability to serve static files and execute dynamic Lua scripts.

Algernon’s lightweight architecture, built-in Lua scripting, and efficient static file serving make it an excellent choice for web applications that need simplicity and performance. Your application is now ready to serve content, execute server-side logic, and handle web requests while maintaining low resource usage.

Remember to follow the production best practices outlined in this guide, regularly monitor your application performance, and optimize your Lua scripts for better performance. With proper configuration, monitoring, and maintenance, Algernon on Klutch.sh will provide a reliable, efficient foundation for your web applications.