A reference implementation demonstrating how to build, version, and distribute self-hosted software using Self-Host Pro.
While this demo uses Laravel, Self-Host Pro works with any containerized application β Node.js, Python, Go, Ruby, or any stack that runs in Docker.
This app showcases the complete workflow for selling self-hosted software:
- Database Persistence β SQLite data survives container restarts
- Version Embedding β App version injected at build time via
composer.json - Automated Builds β GitHub Actions builds and pushes to Self-Host Pro's registry
- Release Strategies β Edge, pre-release, and stable release workflows
The CI/CD setup uses a single reusable workflow called by three trigger files. Check out .github/workflows/ to see:
| File | Trigger | Tags Produced |
|---|---|---|
action_stable-release.yml |
GitHub Release | latest, 1.2.0, 1 |
action_prerelease.yml |
GitHub Pre-release | prerelease, prerelease-v1.0.0-beta |
action_edge.yml |
Push to main |
edge-main |
service_docker-build-and-publish.yml |
Called by above | (reusable build logic) |
Each trigger workflow is ~20 lines β they just pass different tags to the shared build pipeline. Copy a trigger file to add new release channels like nightly or canary.
This project uses Spin for local Docker development. Spin provides a consistent environment that mirrors production.
- Docker & Docker Compose
- Spin
# Clone the repo
git clone https://github.com/selfhostpro/demo-app.git
cd demo-app
# Copy environment file
cp .env.example .env
# Install dependencies
spin run php composer install
spin run node yarn install
# Generate app key and run migrations
spin run php php artisan key:generate
spin run php php artisan migrate
# Seed demo data
spin run php php artisan initialize --force
# Start application servers with Vite
spin upVisit https://laravel.dev.test (add to 127.0.0.1 laravel.dev.test in /etc/hosts if needed).
The project includes two Dockerfiles:
Dockerfile.phpβ Production PHP image with FrankenPHPDockerfile.nodeβ Node.js for building frontend assets
The GitHub Actions workflow handles production builds, but you can build manually:
# Install dependencies first
spin run php composer install --optimize-autoloader --no-dev
spin run node yarn install && yarn build
# Build the image
docker build -t shpcr.io/yourname/app:latest -f Dockerfile.php .
# Push to Self-Host Pro registry
docker login shpcr.io
docker push shpcr.io/yourname/app:latestβββ .github/workflows/ # CI/CD workflows (start here!)
β βββ action_stable-release.yml
β βββ action_prerelease.yml
β βββ action_edge.yml
β βββ service_docker-build-and-publish.yml
βββ app/
β βββ Console/Commands/ # Artisan commands
β βββ Models/ # Eloquent models
βββ resources/
β βββ css/ # Tailwind CSS
β βββ js/ # Globe animation & app JS
β βββ views/ # Blade templates
βββ docker-compose.yml # Base compose config
βββ docker-compose.dev.yml # Development overrides
βββ docker-compose.ci.yml # CI build config
βββ Dockerfile.php # Production PHP image
βββ Dockerfile.node # Node build image
Set the version in composer.json or via environment variable:
{
"version": "1.0.0"
}APP_VERSION=1.0.0The GitHub Actions workflow automatically updates composer.json with the release tag version before building.
# Seed space mission demo data
php artisan initialize [--force]
# Check app status
php artisan status
# Reset to clean state
php artisan reset [--force]