Skip to main content
Self-hosted Stormkit instances provide the flexibility to customize Docker images according to your specific deployment needs. You can build custom images that include additional runtimes, dependencies, tools, or configurations that your applications require.

Understanding Stormkit’s Runtime Management

Stormkit uses mise (formerly rtx) to dynamically install and manage runtimes during application deployment. This approach provides several benefits:
  • Flexible runtime versions - Each project can specify its own runtime version
  • Automatic dependency management - Runtimes are installed on-demand
  • Persistent storage - Dependencies are cached in the home folder for reuse
For most use cases, Stormkit’s dynamic runtime installation via mise is sufficient. Custom images are primarily needed for system-level dependencies that require root access.

Runtime vs Build-time Dependencies

Understanding the distinction between different types of dependencies is crucial: Runtime Dependencies (Managed by mise):
  • Programming language runtimes (Node.js, Python, Go, Rust, etc.)
  • Language-specific package managers (npm, pip, cargo, etc.)
  • Dependencies installed via mise configuration files
  • Tools available through mise plugins
Build-time Dependencies (Require Custom Images):
  • System packages requiring root access
  • Custom build tools and utilities
  • Base system configurations
  • Native libraries and binaries

Official Stormkit Images

Before creating custom images, understand the official Stormkit images available:

ghcr.io/stormkit-io/hosting:latest

  • Purpose: Serves the Stormkit API and deployed applications
  • Responsibilities:
    • Web interface and API endpoints
    • Application hosting and serving
    • TLS certificate management
    • HTTP/HTTPS request handling
  • Optimization: Optimized for production web serving

ghcr.io/stormkit-io/workerserver:latest

  • Purpose: Runs background jobs and deployments
  • Responsibilities:
    • Application builds and deployments
    • Build queue processing
    • Background job execution
    • Deployment pipeline management
  • Optimization: Optimized for build and deployment tasks
Most custom dependencies should be added to the workerserver image, as this is where builds and deployments execute.

When to Customize Images

Custom images are primarily needed for:

System-Level Dependencies

Packages that require root access to install:

Custom Build Tools

Tools not available through standard package managers:

Security Configurations

System-level security hardening and configurations:

Pre-installed System Utilities

Libraries that multiple projects need:
For runtime dependencies like Node.js versions or npm packages, use mise configuration instead of custom images. This provides more flexibility and easier updates.

Persisting Dependencies

Stormkit stores all runtime dependencies in the home folder. To persist these dependencies across upgrades and restarts, mount the home directory:
docker-compose.yaml
Persisting the home directory prevents re-downloading runtimes after container restarts and improves deployment performance.

Creating Custom Images

Basic Custom Image Example

Create a Dockerfile extending the official workerserver image:
Dockerfile
Security Critical: Always switch back to the stormkit user after installing packages. Running as root in production is a security risk.

Advanced Example: Multiple Dependencies

Dockerfile.workerserver

Custom Hosting Image Example

If you need to customize the hosting image:
Dockerfile.hosting

Building Custom Images

1

Create Dockerfile

Create your Dockerfile in your project directory.
2

Build Image Locally

3

Test Image (Optional)

4

Tag for Registry (Optional)

5

Push to Registry (Optional)

Pushing to a registry is optional if you’re building directly on your deployment server.

Configuring Docker Compose

Update your docker-compose.yaml to use custom images:

Option 1: Build from Local Dockerfile

docker-compose.yaml

Option 2: Use Pre-built Image from Registry

docker-compose.yaml

Upgrading Custom Images

1

Pull Latest Base Image

2

Rebuild Custom Image

3

Stop Services

4

Start with New Images

5

Verify Services

The --build flag ensures Docker Compose rebuilds the image if there are changes.

Security Considerations

Follow these security best practices when creating custom images:

Use Official Base Images

Minimize Attack Surface

Always Switch Back to Non-Root User

Keep Images Updated

Scan for Vulnerabilities

Best Practices

Layer Optimization

Combine RUN commands to reduce image layers:

Clean Up Cache

Remove package manager cache to reduce image size:

Use .dockerignore

Create a .dockerignore file to exclude unnecessary files:
.dockerignore

Document Customizations

Add comments explaining why packages are needed:

Troubleshooting

Build Fails: Permission Denied

Cause: Trying to install packages without switching to root. Solution:

Container Crashes After Custom Image

Cause: Not switching back to stormkit user. Solution: Ensure USER stormkit is at the end of your Dockerfile.

Builds Are Slow

Cause: Not using Docker layer caching. Solution:
  • Order Dockerfile commands from least to most frequently changing
  • Use BuildKit: DOCKER_BUILDKIT=1 docker build ...

Large Image Size

Cause: Not cleaning up package manager cache. Solution:

Next Steps

Runtimes

Manage programming language runtimes with mise

Troubleshooting

Common issues and solutions