Deploying Antville
Introduction
Antville is a pioneering open-source weblog hosting platform, affectionately known as the “Queen Mum of Weblog Hosting Systems.” Built on the Helma Object Publisher framework, Antville provides a robust, multi-user blogging environment that has powered high-traffic sites for over two decades, including antville.org and other community hosting platforms.
Deploying Antville on Klutch.sh gives you a scalable, production-ready blogging platform with automatic HTTPS, persistent storage for your content, and seamless PostgreSQL database integration. The platform supports multiple blogs per installation, user management, customizable skins, and a rich set of features for content management.
This guide walks you through deploying Antville using a custom Dockerfile on Klutch.sh, setting up a PostgreSQL database, configuring persistent storage, and best practices for running this Java-based application in production.
What You’ll Learn
- How to deploy Antville with Helma Object Publisher using a Dockerfile on Klutch.sh
- Setting up PostgreSQL as the database backend
- Configuring persistent storage for content and media files
- Setting up environment variables for database connectivity and SMTP
- Best practices for production deployment and performance
Prerequisites
Before you begin, ensure you have:
- A Klutch.sh account
- A GitHub repository (can be a new empty repo)
- Basic familiarity with Docker and Java applications
- (Optional) SMTP server credentials for email notifications
Understanding Antville Architecture
Antville consists of several key components:
- Helma Object Publisher: A Java-based application server using Rhino (server-side JavaScript) with an embedded Jetty web server
- Application Layer: JavaScript-based application code running on Helma, handling blog logic, user management, and content rendering
- Database: PostgreSQL (recommended) or MySQL/MariaDB for storing blog posts, users, comments, and metadata
- Storage: File-based storage for images, media uploads, and configuration
The application runs on port 8080 by default via the embedded Jetty server, making it straightforward to deploy on Klutch.sh.
Step 1: Set Up PostgreSQL Database
Antville requires a database for storing blog content, user accounts, and metadata. We recommend PostgreSQL for best performance.
Option A: Deploy PostgreSQL on Klutch.sh (Recommended)
-
Log in to Klutch.sh and navigate to the dashboard.
-
Create a new project (if you don’t have one) or select an existing project.
-
Create a PostgreSQL TCP app:
- Click “New App”
- Select “TCP” as the traffic type
- Connect a GitHub repository containing a PostgreSQL Dockerfile, or use the official image
-
Create a
Dockerfilefor PostgreSQL in a separate repository: -
Configure a persistent volume for data:
- Mount Path:
/var/lib/postgresql/data - Size: 10 GB (adjust based on expected content volume)
- Mount Path:
-
Set environment variables:
- Deploy the PostgreSQL app. Note the app URL for connecting Antville (e.g.,
postgres-app.klutch.sh:8000).
FROM postgres:16-alpine
# Set default environment variablesENV POSTGRES_DB=antvilleENV POSTGRES_USER=antville
# Expose PostgreSQL portEXPOSE 5432POSTGRES_PASSWORD=your-secure-passwordOption B: Use an External PostgreSQL Service
You can also use managed PostgreSQL services like:
If using an external service, note the connection details (host, port, database, username, password) for later configuration.
Step 2: Prepare Your GitHub Repository
-
Create a new GitHub repository for your Antville deployment.
-
Create a
Dockerfilein the root of your repository: - Create the
apps.propertiesfile: - Create the
server.propertiesfile: - Create the
db.propertiesfile: - Create a startup script
start.sh: - Update the Dockerfile to use the startup script:
- (Optional) Create a
.dockerignorefile: - Commit and push your changes to GitHub:
FROM eclipse-temurin:17-jdk-alpine AS builder
# Install build dependenciesRUN apk add --no-cache bash curl git rsync nodejs npm
# Set working directoryWORKDIR /build
# Clone Helma Object PublisherRUN git clone --depth 1 https://github.com/antville/helma.git
# Build HelmaWORKDIR /build/helmaRUN chmod +x gradlew && \ ./gradlew install
# Download AntvilleWORKDIR /buildRUN curl -L https://github.com/antville/antville/archive/refs/heads/main.tar.gz | tar xz && \ mv antville-main antville
# Download PostgreSQL JDBC driverRUN curl -L -o /build/helma/build/install/helma/lib/ext/postgresql.jar \ https://jdbc.postgresql.org/download/postgresql-42.7.1.jar
# Production stageFROM eclipse-temurin:17-jre-alpine
# Install runtime dependenciesRUN apk add --no-cache bash
# Create helma userRUN addgroup -S helma && adduser -S helma -G helma
# Set working directoryWORKDIR /helma
# Copy Helma installation from builderCOPY --from=builder /build/helma/build/install/helma /helma
# Copy Antville applicationCOPY --from=builder /build/antville /helma/apps/antville
# Create necessary directoriesRUN mkdir -p /helma/apps/antville/static \ && mkdir -p /helma/db \ && mkdir -p /helma/log
# Copy configuration filesCOPY apps.properties /helma/apps.propertiesCOPY server.properties /helma/server.propertiesCOPY db.properties /helma/apps/antville/code/db.properties
# Set permissionsRUN chown -R helma:helma /helma
# Switch to non-root userUSER helma
# Expose Helma portEXPOSE 8080
# Start HelmaCMD ["./bin/helma"]# Antville application configurationantvilleantville.mountpoint = /antville.repository.0 = apps/antville/code/antville.repository.1 = modules/jala/code/antville.static = apps/antville/staticantville.staticMountpoint = /staticantville.staticIndex = index.html# Helma server configuration# HTTP porthttp.port = 8080
# SMTP server for email notifications (configure via environment variable)smtp = ${SMTP_HOST}
# Country settingcountry = US
# Language settinglanguage = en
# Logginglogdir = logloglevel = info# PostgreSQL database configurationantville.url = jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}antville.driver = org.postgresql.Driverantville.user = ${DB_USER}antville.password = ${DB_PASSWORD}
# Connection pool settingsantville.maxActive = 50antville.maxIdle = 10antville.minIdle = 5antville.maxWait = 10000#!/bin/bashset -e
# Substitute environment variables in configuration filesenvsubst < /helma/server.properties.template > /helma/server.propertiesenvsubst < /helma/apps/antville/code/db.properties.template > /helma/apps/antville/code/db.properties
# Initialize database if neededif [ "$INIT_DATABASE" = "true" ]; then echo "Initializing Antville database..." PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -f /helma/apps/antville/db/postgre.sqlfi
# Start Helmaexec ./bin/helmaFROM eclipse-temurin:17-jdk-alpine AS builder
# Install build dependenciesRUN apk add --no-cache bash curl git rsync nodejs npm
# Set working directoryWORKDIR /build
# Clone Helma Object PublisherRUN git clone --depth 1 https://github.com/antville/helma.git
# Build HelmaWORKDIR /build/helmaRUN chmod +x gradlew && \ ./gradlew install
# Download AntvilleWORKDIR /buildRUN curl -L https://github.com/antville/antville/archive/refs/heads/main.tar.gz | tar xz && \ mv antville-main antville
# Download PostgreSQL JDBC driverRUN curl -L -o /build/helma/build/install/helma/lib/ext/postgresql.jar \ https://jdbc.postgresql.org/download/postgresql-42.7.1.jar
# Production stageFROM eclipse-temurin:17-jre-alpine
# Install runtime dependenciesRUN apk add --no-cache bash gettext postgresql-client
# Create helma userRUN addgroup -S helma && adduser -S helma -G helma
# Set working directoryWORKDIR /helma
# Copy Helma installation from builderCOPY --from=builder /build/helma/build/install/helma /helma
# Copy Antville applicationCOPY --from=builder /build/antville /helma/apps/antville
# Create necessary directoriesRUN mkdir -p /helma/apps/antville/static \ && mkdir -p /helma/db \ && mkdir -p /helma/log
# Copy configuration templatesCOPY apps.properties /helma/apps.propertiesCOPY server.properties /helma/server.properties.templateCOPY db.properties /helma/apps/antville/code/db.properties.templateCOPY start.sh /helma/start.sh
# Set permissionsRUN chmod +x /helma/start.sh && \ chown -R helma:helma /helma
# Switch to non-root userUSER helma
# Expose Helma portEXPOSE 8080
# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD wget --quiet --tries=1 --spider http://localhost:8080/ || exit 1
# Start Helma using the startup scriptCMD ["/helma/start.sh"].git.github*.md.env.env.localnode_modulesgit add .git commit -m "Add Antville deployment configuration for Klutch.sh"git push origin mainStep 3: Create Your App on Klutch.sh
-
Log in to Klutch.sh and navigate to the dashboard.
-
Create a new project (if you don’t have one already) by clicking “New Project” and providing a project name.
-
Create a new app within your project by clicking “New App”.
-
Connect your GitHub repository by selecting it from the list of available repositories.
-
Configure the build settings:
- Klutch.sh will automatically detect the Dockerfile in your repository root
- The build will use this Dockerfile automatically
-
Set the internal port to
8080(Helma’s default port). This is the port that traffic will be routed to within the container. -
Select HTTP traffic for the app’s traffic type.
Step 4: Configure Persistent Storage
Antville stores uploaded images, media files, and logs in the filesystem. Configure persistent storage to retain these across deployments.
-
In your app settings, navigate to the “Volumes” section.
-
Add a persistent volume for static files:
- Mount Path:
/helma/apps/antville/static - Size: 10 GB (adjust based on expected media uploads)
- Mount Path:
-
Add another persistent volume for logs (optional but recommended):
- Mount Path:
/helma/log - Size: 1 GB
- Mount Path:
-
Save the volume configuration.
The /helma/apps/antville/static directory contains:
- Uploaded images and media files
- User avatars
- Custom theme assets
- Site-specific static content
For more details on managing persistent storage, see the Volumes Guide.
Step 5: Configure Environment Variables
Configure the necessary environment variables for database connectivity, SMTP, and application settings.
-
In your app settings, navigate to the “Environment Variables” section.
-
Add database connection variables:
- Add SMTP configuration (for email notifications):
- Add initialization flag (for first deployment only):
- Mark sensitive values as secrets in the Klutch.sh UI to prevent them from appearing in logs.
# PostgreSQL Database ConfigurationDB_HOST=postgres-app.klutch.shDB_PORT=8000DB_NAME=antvilleDB_USER=antvilleDB_PASSWORD=your-secure-database-passwordIf using a Klutch.sh-hosted PostgreSQL TCP app, use your app’s hostname and port 8000.
# SMTP ConfigurationSMTP_HOST=smtp.example.comFor production email delivery, consider using services like:
# Set to 'true' only for the first deployment to initialize the databaseINIT_DATABASE=trueImportant: After the initial deployment, remove or set INIT_DATABASE=false to prevent database reinitialization.
Step 6: Initialize the Database
Before deploying Antville, you need to initialize the database schema. You have two options:
Option A: Automatic Initialization (via INIT_DATABASE)
- Set
INIT_DATABASE=truein your environment variables - Deploy the application
- After successful deployment, set
INIT_DATABASE=falseor remove the variable - Redeploy to apply the change
Option B: Manual Initialization
- Connect to your PostgreSQL database using a client tool or terminal:
- Download and run the schema script from the Antville repository:
- The script creates:
- All necessary tables (users, sites, stories, comments, etc.)
- Default indexes for performance
- Initial user account with password ‘antville’
psql -h postgres-app.klutch.sh -p 8000 -U antville -d antville-- Run the PostgreSQL schema script-- Download from: https://github.com/antville/antville/blob/main/db/postgre.sqlStep 7: Deploy Your Application
-
Review your configuration to ensure all settings are correct:
- Dockerfile is detected
- Internal port is set to
8080 - Persistent volumes are configured
- Environment variables are set
- Traffic type is set to HTTP
-
Click “Deploy” to start the build and deployment process.
-
Monitor the build logs to ensure the deployment completes successfully. The build typically takes 5-10 minutes due to Java compilation.
-
Wait for the deployment to complete. Once done, you’ll see your app URL (e.g.,
https://example-app.klutch.sh).
Step 8: Initial Setup and Configuration
-
Access your Antville instance by navigating to your app URL (e.g.,
https://example-app.klutch.sh). -
Create your first user account:
- The first user created automatically receives administrator privileges
- Choose a strong password
- This account will manage the entire Antville installation
-
Configure your site:
- Set up site preferences
- Choose a default skin/theme
- Configure site metadata
-
Create your first blog:
- Navigate to site management
- Create a new blog (also called “site” in Antville)
- Customize the blog settings and appearance
-
Start publishing:
- Create your first story/blog post
- Upload images
- Manage comments
Getting Started: Sample Code
Accessing Antville via API
Antville exposes its functionality through a JavaScript-based API. Here are some common operations:
Creating a Story Programmatically
// Helma server-side JavaScript examplevar story = new Story();story.title = "My First Post";story.text = "Welcome to my new blog powered by Antville!";story.status = "public";story.creator = session.user;story.save();Fetching Recent Stories
// Get the 10 most recent storiesvar stories = res.handlers.site.stories.list(0, 10);for each (var story in stories) { res.write(story.title + "<br>");}Custom Skin Development
Antville uses a skin-based templating system. Create custom themes by modifying skin files:
<!-- Example main.skin file --><!DOCTYPE html><html><head> <title><% response.title %></title> <link rel="stylesheet" href="<% site.staticUrl %>style.css"></head><body> <header> <h1><% site.title %></h1> <nav><% site.navigation %></nav> </header>
<main> <% response.body %> </main>
<footer> <p>Powered by Antville</p> </footer></body></html>Managing Users
// Create a new uservar user = new User();user.name = "newuser";user.email = "user@example.com";user.hash = User.prototype.hashPassword("securepassword");user.save();
// Grant membership to a sitevar membership = new Membership();membership.user = user;membership.site = res.handlers.site;membership.role = "contributor";membership.save();Advanced Configuration
Custom Dockerfile with MySQL Support
If you prefer MySQL/MariaDB instead of PostgreSQL, modify the Dockerfile:
FROM eclipse-temurin:17-jdk-alpine AS builder
# Install build dependenciesRUN apk add --no-cache bash curl git rsync nodejs npm
WORKDIR /build
# Clone and build HelmaRUN git clone --depth 1 https://github.com/antville/helma.gitWORKDIR /build/helmaRUN chmod +x gradlew && ./gradlew install
# Download AntvilleWORKDIR /buildRUN curl -L https://github.com/antville/antville/archive/refs/heads/main.tar.gz | tar xz && \ mv antville-main antville
# Download MySQL JDBC driverRUN curl -L -o /build/helma/build/install/helma/lib/ext/mysql-connector.jar \ https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.2.0/mysql-connector-j-8.2.0.jar
# Production stageFROM eclipse-temurin:17-jre-alpine
RUN apk add --no-cache bash gettext mysql-client
RUN addgroup -S helma && adduser -S helma -G helma
WORKDIR /helma
COPY --from=builder /build/helma/build/install/helma /helmaCOPY --from=builder /build/antville /helma/apps/antville
RUN mkdir -p /helma/apps/antville/static \ && mkdir -p /helma/db \ && mkdir -p /helma/log
COPY apps.properties /helma/apps.propertiesCOPY server.properties /helma/server.properties.templateCOPY db-mysql.properties /helma/apps/antville/code/db.properties.templateCOPY start.sh /helma/start.sh
RUN chmod +x /helma/start.sh && \ chown -R helma:helma /helma
USER helma
EXPOSE 8080
CMD ["/helma/start.sh"]Create db-mysql.properties:
# MySQL database configurationantville.url = jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}antville.driver = com.mysql.cj.jdbc.Driverantville.user = ${DB_USER}antville.password = ${DB_PASSWORD}
# Connection pool settingsantville.maxActive = 50antville.maxIdle = 10antville.minIdle = 5antville.maxWait = 10000Update apps.properties for MySQL compatibility:
# Antville application configuration with MySQLantvilleantville.mountpoint = /antville.repository.0 = apps/antville/code/antville.repository.1 = apps/antville/db/my.compat/antville.repository.2 = modules/jala/code/antville.static = apps/antville/staticantville.staticMountpoint = /staticantville.staticIndex = index.htmlPerformance Tuning
Optimize Helma for production workloads by adjusting server.properties:
# HTTP configurationhttp.port = 8080http.maxConnections = 200http.keepAlive = true
# Thread pool settingsminThreads = 10maxThreads = 100
# Cache configurationcachesize = 1000
# Session configurationsessionTimeout = 60
# Logginglogdir = logloglevel = warn
# SMTPsmtp = ${SMTP_HOST}JVM Memory Settings
For larger installations, add JVM options by modifying the startup script:
#!/bin/bashset -e
# JVM memory settingsexport JAVA_OPTS="-Xms512m -Xmx2g -XX:+UseG1GC"
# Substitute environment variablesenvsubst < /helma/server.properties.template > /helma/server.propertiesenvsubst < /helma/apps/antville/code/db.properties.template > /helma/apps/antville/code/db.properties
# Start Helma with optimized settingsexec ./bin/helma $JAVA_OPTSProduction Best Practices
Security
- Change default credentials: Update the default ‘antville’ database password immediately
- Use HTTPS only: Klutch.sh provides automatic HTTPS for all apps
- Implement strong passwords: Require strong passwords for all user accounts
- Regular updates: Keep Helma and Antville updated to the latest versions
- Secure environment variables: Mark database credentials and secrets as protected
Performance
- Database indexing: Ensure proper indexes are created (included in schema scripts)
- Connection pooling: Configure appropriate pool sizes based on traffic
- Static file caching: Leverage Klutch.sh CDN for static assets
- Monitor memory usage: Adjust JVM heap size based on actual usage
Backups
- Database backups: Regularly backup your PostgreSQL database
- File backups: Backup the
/helma/apps/antville/staticdirectory - Configuration backups: Keep copies of your configuration files
# Example PostgreSQL backup commandpg_dump -h $DB_HOST -p $DB_PORT -U $DB_USER $DB_NAME > antville_backup.sqlMonitoring
- Application logs: Monitor
/helma/logfor errors and warnings - Database performance: Track query performance and connection usage
- Resource utilization: Monitor CPU and memory through Klutch.sh dashboard
Troubleshooting
Application Won’t Start
Issue: Container starts but application doesn’t respond
Solutions:
- Verify port 8080 is correctly configured
- Check database connectivity with environment variables
- Review startup logs for Java exceptions
- Ensure JDBC driver is properly installed
Database Connection Errors
Issue: Cannot connect to PostgreSQL
Solutions:
- Verify database hostname and port (use 8000 for Klutch.sh TCP apps)
- Check database credentials are correct
- Ensure PostgreSQL is running and accessible
- Test connection manually with psql
psql -h postgres-app.klutch.sh -p 8000 -U antville -d antville -c "SELECT 1"Out of Memory Errors
Issue: Application crashes with OutOfMemoryError
Solutions:
- Increase JVM heap size in startup script
- Scale up the instance size in Klutch.sh
- Review for memory leaks in custom code
- Reduce cache sizes if necessary
Images Not Loading
Issue: Uploaded images return 404 errors
Solutions:
- Verify persistent volume is mounted to
/helma/apps/antville/static - Check file permissions in the static directory
- Ensure staticMountpoint is configured in apps.properties
- Review the static URL configuration
Slow Performance
Issue: Pages load slowly
Solutions:
- Enable database query logging to identify slow queries
- Increase connection pool size
- Add database indexes for frequently queried fields
- Consider caching strategies for heavily accessed content
Scaling Considerations
Vertical Scaling
For increased traffic, scale up your instance:
- Increase CPU and memory allocation
- Expand database resources
- Increase storage volume size
Database Optimization
-- Add indexes for common queriesCREATE INDEX idx_story_created ON story(created);CREATE INDEX idx_story_site ON story(site_id);CREATE INDEX idx_comment_story ON comment(story_id);CREATE INDEX idx_user_email ON "user"(email);Static Asset Optimization
- Use CDN for serving static assets
- Compress images before upload
- Enable browser caching headers
Local Development with Docker Compose
For local testing before deploying to Klutch.sh, use Docker Compose:
version: '3.8'
services: antville: build: . ports: - "8080:8080" environment: - DB_HOST=postgres - DB_PORT=5432 - DB_NAME=antville - DB_USER=antville - DB_PASSWORD=devpassword - SMTP_HOST=mailhog - INIT_DATABASE=true volumes: - antville_static:/helma/apps/antville/static depends_on: - postgres - mailhog
postgres: image: postgres:16-alpine environment: - POSTGRES_DB=antville - POSTGRES_USER=antville - POSTGRES_PASSWORD=devpassword volumes: - postgres_data:/var/lib/postgresql/data
mailhog: image: mailhog/mailhog ports: - "1025:1025" - "8025:8025"
volumes: antville_static: postgres_data:Run locally with:
docker-compose up -dAccess Antville at http://localhost:8080 and MailHog at http://localhost:8025 for email testing.
Note: Docker Compose is for local development only. Deploy to Klutch.sh using the Dockerfile approach described in this guide.
Updating Antville
To update to a newer version of Antville:
- Update the Dockerfile to pull the latest Antville release:
- Commit and push the changes:
-
Redeploy through the Klutch.sh dashboard.
-
Verify the update by checking the application logs and testing functionality.
# In the builder stage, use a specific release tagRUN curl -L https://github.com/antville/antville/archive/refs/tags/v1.6.tar.gz | tar xz && \ mv antville-1.6 antvillegit add Dockerfilegit commit -m "Update Antville to version 1.6"git push origin mainResources
- Antville GitHub Repository
- Helma Object Publisher Repository
- Antville.org - Official Community
- Helma Documentation (Archive)
- Klutch.sh Quick Start Guide
- Klutch.sh Volumes Guide
- PostgreSQL Deployment Guide
Conclusion
You now have a fully functional Antville deployment running on Klutch.sh with PostgreSQL database integration and persistent storage. This classic weblog hosting platform provides:
- Multi-user blogging capabilities
- Customizable skins and themes
- Image and media management
- Comment system
- User management and permissions
- Automatic HTTPS and scalable infrastructure
Antville’s proven architecture, which has powered high-traffic sites for over two decades, combined with Klutch.sh’s modern deployment infrastructure, gives you a reliable and maintainable blogging platform.
For community support and discussions, visit the Antville community or explore the GitHub repositories for both Antville and Helma.