{"id":28991258,"url":"https://github.com/elitan/luma","last_synced_at":"2025-06-25T01:03:20.870Z","repository":{"id":293282760,"uuid":"983417313","full_name":"elitan/luma","owner":"elitan","description":"Ship Docker Anywhere","archived":false,"fork":false,"pushed_at":"2025-06-06T08:37:04.000Z","size":92734,"stargazers_count":260,"open_issues_count":0,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-06-24T11:41:10.247Z","etag":null,"topics":["bun","cloud","docker","go","typescript"],"latest_commit_sha":null,"homepage":"http://myluma.cloud","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elitan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-14T10:57:43.000Z","updated_at":"2025-06-10T19:51:42.000Z","dependencies_parsed_at":"2025-05-15T22:01:35.867Z","dependency_job_id":null,"html_url":"https://github.com/elitan/luma","commit_stats":null,"previous_names":["elitan/luma"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/elitan/luma","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fluma","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fluma/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fluma/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fluma/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elitan","download_url":"https://codeload.github.com/elitan/luma/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elitan%2Fluma/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261783371,"owners_count":23208947,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","cloud","docker","go","typescript"],"created_at":"2025-06-25T01:02:47.646Z","updated_at":"2025-06-25T01:03:20.862Z","avatar_url":"https://github.com/elitan.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Luma: Ship Docker Anywhere ⚡\n\nZero-downtime deployments and automatic HTTPS on your own servers.\n\n```\n❯ luma deploy --force\nUsing Git SHA for release ID: 80d0f8c\nStarting deployment with release 80d0f8c\n\n[✓] Configuration loaded (1ms)\n[✓] Git status verified (4ms)\n[✓] Infrastructure ready (879ms)\n[✓] web → web:80d0f8c (1.8s)\n[✓] Building Images (1.8s)\n[✓] App State Reconciliation (884ms)\n  └─ web → 157.180.25.101\n     ├─ [✓] Loading web image (1.7s)\n     ├─ [✓] Zero-downtime deployment of web (3.5s)\n     └─ [✓] Configuring proxy for web (805ms)\n[✓] Deploying Apps (6.2s)\n[✓] Deployment completed successfully in 9.8s\n\nYour app is live at:\n  └─ https://test.eliasson.me\n```\n\nLuma automatically handles:\n\n- ✅ Zero-downtime blue-green deployments\n- ✅ Automatic SSL certificates via Let's Encrypt\n- ✅ Health checks and automatic rollbacks\n- ✅ Docker image building and secure transfer\n- ✅ Multi-server deployments\n\n---\n\n## 🚀 Quick Start\n\n### 1. Install Luma\n\n```bash\nnpm install -g @elitan/luma\n```\n\n### 2. Initialize your project\n\n```bash\ncd your-project\nluma init\n```\n\nThis creates:\n\n- `luma.yml` - Your deployment configuration\n- `.luma/secrets` - Secure credentials (add to `.gitignore`)\n\n### 3. Configure your app\n\nEdit `luma.yml`:\n\n```yaml\nname: my-app\n\napps:\n  web:\n    image: my-app/web\n    servers:\n      - your-server.com\n    build:\n      context: .\n      dockerfile: Dockerfile\n    proxy:\n      hosts:\n        - myapp.com\n      app_port: 3000\n```\n\n### 4. Set up your server\n\n```bash\nluma setup\n```\n\nLuma will:\n\n- Install Docker if needed\n- Set up the reverse proxy\n- Start services\n\n### 5. Deploy!\n\n```bash\nluma deploy\n```\n\nWatch as Luma builds, deploys, and switches traffic with zero downtime.\n\n---\n\n## 📋 Prerequisites\n\n- **Local machine**: Bun or Node.js 18+\n- **Target servers**:\n  - Ubuntu/Debian Linux\n  - SSH access with sudo privileges\n  - Ports 80 and 443 open\n\n---\n\n## 🆚 Why Luma vs Alternatives?\n\n### vs Kamal (37signals)\n\n- **TypeScript/Bun** instead of Ruby\n- **Registry-less deployments** - no need for external Docker registries\n\n### vs Vercel/Netlify\n\n- **Your own servers** - full control, no vendor lock-in\n- **Any Docker app** - not limited to specific frameworks\n- **Cost-effective** - pay only for your servers\n- **No cold starts** - your containers are always running\n\n### vs Docker Compose\n\n- **Zero-downtime deployments** - compose restarts cause downtime\n- **Multi-server support** - deploy across multiple machines\n- **Automatic SSL** and reverse proxy included\n- **Git-based releases** and rollback capabilities\n\n---\n\n## 🎯 Core Concepts\n\n### Apps vs Services\n\n**Apps** are your main applications (web servers, APIs) that you build and deploy with zero-downtime:\n\n```yaml\napps:\n  web:\n    image: my-app/web\n    build:\n      context: .\n      dockerfile: Dockerfile\n    proxy:\n      hosts:\n        - example.com\n      app_port: 3000\n\n  api:\n    image: my-app/api\n    build:\n      context: ./api\n    proxy:\n      hosts:\n        - api.example.com\n      app_port: 8080\n```\n\n**Services** are supporting infrastructure (databases, caches) that use pre-built images:\n\n```yaml\nservices:\n  postgres:\n    image: postgres:15\n    environment:\n      secret: [POSTGRES_PASSWORD]\n    volumes:\n      - postgres_data:/var/lib/postgresql/data\n\n  redis:\n    image: redis:7\n```\n\n### Zero-Downtime Deployments\n\nLuma automatically uses blue-green deployment for apps:\n\n1. **Build and transfer** your Docker image securely to servers\n2. **Deploy new version** alongside the current one\n3. **Health check** the new version via configured health endpoint\n4. **Switch traffic** atomically (sub-millisecond)\n5. **Clean up** old version\n\nNo Docker registry required - images are transferred directly!\n\n### Registry-Free Operation\n\nBuilt apps are transferred using secure Docker save/load:\n\n- **Build locally** - your Docker images are built on your machine\n- **Transfer securely** - images are saved as tar archives and uploaded via SSH\n- **Load remotely** - Docker loads the image directly on your servers\n- **No registry needed** - eliminates external dependencies and credentials\n\nServices can still use registries for pre-built images like `postgres:15`.\n\n### Automatic SSL\n\nLuma includes a smart reverse proxy that automatically:\n\n- Obtains SSL certificates via Let's Encrypt\n- Routes traffic to your apps\n- Handles health checks\n- Manages zero-downtime deployments with blue-green switching\n\n### Health Checks\n\nLuma performs automatic health checks during deployments to ensure zero-downtime deployments. Your application must implement a health check endpoint that returns HTTP 200 when healthy.\n\nThe default health check endpoint is `/up` but you can configure it to any path you want.\n\n```yaml\napps:\n  api:\n    health_check:\n      path: /health # Health check endpoint (default: /up)\n```\n\n**Health Check Behavior (Automatic):**\n\n- **Method**: HTTP GET request\n- **Success criteria**: HTTP 200 response\n- **Timeout**: 5 seconds\n- **Retries**: 3 attempts\n- **Port**: Uses the configured `app_port` (defaults to 80)\n\nThe only configurable option is:\n\n- **path**: Health check endpoint path (default: `/up`)\n\nAll other health check behavior is handled automatically by Luma to ensure reliable deployments.\n\n---\n\n## 📖 Configuration Reference\n\n### Basic Configuration\n\n```yaml\nname: my-project # Required: Project name\n\n# Optional: Global settings\nssh:\n  username: deploy # SSH user (default: root)\n  port: 22 # SSH port\n\n# Optional: Docker registry (only needed for services using private registries)\ndocker:\n  registry: ghcr.io # Docker registry\n  username: myuser # Registry username\n\napps:\n  web:\n    image: my-app/web # Docker image name\n    servers:\n      - server1.com\n      - server2.com # Target servers\n\n    # Build configuration (apps are built locally and transferred)\n    build:\n      context: .\n      dockerfile: Dockerfile\n      platform: linux/amd64\n\n    # Proxy configuration for web apps\n    proxy:\n      hosts:\n        - example.com\n        - www.example.com\n      app_port: 3000\n\n    # Environment variables\n    environment:\n      plain:\n        - NODE_ENV=production\n        - PORT=3000\n      secret:\n        - DATABASE_URL # From .luma/secrets\n        - API_KEY\n\n    # Health check (optional)\n    health_check:\n      path: /health # Health check endpoint (default: /up)\n\nservices:\n  database:\n    image: postgres:15\n    servers:\n      - db.example.com\n    environment:\n      secret:\n        - POSTGRES_PASSWORD\n    ports:\n      - \"5432:5432\"\n    volumes:\n      - postgres_data:/var/lib/postgresql/data\n```\n\n### Secrets Management\n\nStore sensitive values in `.luma/secrets`:\n\n```bash\n# .luma/secrets\nDATABASE_URL=postgres://user:pass@localhost:5432/myapp\nAPI_KEY=supersecretkey\n# Only needed if using private registries for services\nDOCKER_REGISTRY_PASSWORD=myregistrypassword\n```\n\n**Important**: Add `.luma/secrets` to your `.gitignore`!\n\n---\n\n## 🛠️ Commands\n\n### `luma init`\n\nInitialize a new project with configuration files.\n\n### `luma setup [service...]`\n\nPrepare servers for deployment. Installs Docker, creates networks, sets up the proxy.\n\n```bash\nluma setup              # Set up all servers\nluma setup web api      # Set up only servers for web and api\n```\n\n### `luma deploy [app...]`\n\nDeploy apps or services with zero downtime.\n\n```bash\nluma deploy             # Deploy all apps\nluma deploy web         # Deploy specific app\nluma deploy --services  # Deploy services instead\nluma deploy --force     # Skip git status checks\nluma deploy --verbose   # Detailed logging\n```\n\n### `luma status [app...]`\n\nCheck the status of your deployments.\n\n```bash\nluma status             # Status of all apps\nluma status web         # Status of specific app\n\n# Example output:\n📱 App: web\n   Status: ✅ RUNNING (green active)\n   Replicas: 2/2 running\n   Servers: server1.com, server2.com\n```\n\n---\n\n## 🏗️ Examples\n\n### Simple Web App\n\n```yaml\nname: blog\napps:\n  web:\n    image: my-blog\n    servers:\n      - server.com\n    build:\n      context: .\n    proxy:\n      hosts:\n        - blog.com\n      app_port: 3000\n    environment:\n      secret: [DATABASE_URL]\n```\n\n### Full-Stack App with Database\n\n```yaml\nname: ecommerce\n\napps:\n  web:\n    image: ecommerce/frontend\n    servers:\n      - web1.com\n      - web2.com\n    build:\n      context: ./frontend\n    proxy:\n      hosts:\n        - shop.com\n        - www.shop.com\n      app_port: 3000\n\n  api:\n    image: ecommerce/backend\n    servers:\n      - api.com\n    build:\n      context: ./backend\n    proxy:\n      hosts:\n        - api.shop.com\n      app_port: 8080\n    environment:\n      secret: [DATABASE_URL, JWT_SECRET]\n\nservices:\n  postgres:\n    image: postgres:15\n    servers:\n      - db.com\n    environment:\n      secret: [POSTGRES_PASSWORD]\n    volumes:\n      - postgres_data:/var/lib/postgresql/data\n\n  redis:\n    image: redis:7\n    servers:\n      - cache.com\n```\n\n### Microservices with Load Balancing\n\n```yaml\nname: platform\n\napps:\n  user-service:\n    image: platform/users\n    replicas: 3\n    servers:\n      - app1.com\n      - app2.com\n    build:\n      context: ./services/users\n    proxy:\n      hosts:\n        - users.platform.com\n      app_port: 8080\n\n  order-service:\n    image: platform/orders\n    replicas: 2\n    servers:\n      - app1.com\n      - app2.com\n    build:\n      context: ./services/orders\n    proxy:\n      hosts:\n        - orders.platform.com\n      app_port: 8081\n```\n\n---\n\n## 🔒 Security Best Practices\n\n### Server Preparation Guide (from root)\n\nFollow these steps to securely prepare your server for Luma deployments. All commands should be run as the `root` user (or with `sudo`).\n\n1. **Create a dedicated user for Luma:**\n\n```bash\nsudo adduser luma\n# Follow the prompts to set a password (it will be disabled later) and user details.\nsudo usermod -aG sudo luma # Add luma to the sudo group\n```\n\n2. **Install Docker Engine:**\n\nLuma requires Docker to be installed on your target servers.\n\n```bash\n# Update package lists\nsudo apt-get update\n\n# Install prerequisites\nsudo apt-get install -y ca-certificates curl\n\n# Create keyrings directory\nsudo install -m 0755 -d /etc/apt/keyrings\n\n# Add Docker's official GPG key\nsudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc\nsudo chmod a+r /etc/apt/keyrings/docker.asc\n\n# Add Docker's stable repository\necho \\\n  \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \\\n  $(. /etc/os-release \u0026\u0026 echo \"$VERSION_CODENAME\") stable\" | \\\n  sudo tee /etc/apt/sources.list.d/docker.list \u003e /dev/null\n\n# Update package lists again\nsudo apt-get update\n\n# Install Docker CE with all plugins\nsudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n\n# Add the luma user to the docker group\nsudo usermod -aG docker luma\n\n# Verify installation\nsudo docker run hello-world\n```\n\n_Note: You might need to log out and log back in as the `luma` user for the group changes to take effect, or use `newgrp docker` in the `luma` user's session._\n\n3. **Set up SSH Key-Based Authentication for `luma`:**\n\n   **Prerequisites:** This step assumes you already have SSH keys generated on your local machine. If you don't have SSH keys yet, generate them first:\n\n```bash\nssh-keygen -t rsa -b 4096 -C \"your_email@example.com\"\n# Follow the prompts. It's recommended to use a passphrase for your key.\n```\n\n**Copy your public key to the server:**\nReplace `your-server.com` with your server's IP address or hostname.\n\n```bash\nssh-copy-id luma@your-server.com\n```\n\nThis command will copy your local machine's public SSH key to the `luma` user's `~/.ssh/authorized_keys` file on the server.\n\n4. **Secure SSH Configuration:**\n\nDisable password authentication and make other security improvements to your SSH server. Edit the SSH daemon configuration file (`/etc/ssh/sshd_config`) on the server:\n\n```bash\nsudo nano /etc/ssh/sshd_config\n```\n\nMake the following changes:\n\n```\nPermitRootLogin no\nPasswordAuthentication no\nPubkeyAuthentication yes\nChallengeResponseAuthentication no\nUsePAM no # If you are sure you don't need PAM for SSH\n```\n\nAfter saving the changes, restart the SSH service:\n\n```bash\nsudo systemctl restart ssh\n```\n\n**Important:** Ensure your SSH key authentication is working correctly before disabling password authentication, or you could lock yourself out of the server. Test by logging in from a new terminal window: `ssh luma@your-server.com`.\n\n5. **Install Fail2Ban:**\n\nFail2Ban helps protect your server from brute-force attacks.\n\n```bash\nsudo apt-get update\nsudo apt-get install -y fail2ban\nsudo systemctl enable fail2ban\nsudo systemctl start fail2ban\n```\n\nFail2Ban works out-of-the-box with default settings for SSH. You can customize its configuration in `/etc/fail2ban/jail.local`.\n\n6. **Configure Luma:**\n\nIn your `luma.yml` file, ensure you specify the `luma` user for SSH connections:\n\n```yaml\nssh:\n  username: luma\n  # port: 22 # If you changed the SSH port\n```\n\nAfter completing these steps, your server will be more secure and ready for Luma deployments.\n\n### Secrets Management\n\n- Never commit `.luma/secrets` to version control\n- Use environment-specific secrets\n\n## 📚 Advanced Usage\n\n### Multi-Environment Deployments\n\n```yaml\n# luma.staging.yml\nname: myapp-staging\napps:\n  web:\n    image: myapp/web\n    build:\n      context: .\n    servers:\n      - staging.myapp.com\n\n# luma.production.yml\nname: myapp-prod\napps:\n  web:\n    image: myapp/web\n    build:\n      context: .\n    servers:\n      - prod1.myapp.com\n      - prod2.myapp.com\n```\n\nDeploy with:\n\n```bash\nluma deploy -c luma.staging.yml\nluma deploy -c luma.production.yml\n```\n\n### Using Docker Registries (Optional)\n\nFor services that need private registries or when you prefer registry-based workflows:\n\n```yaml\n# Global registry configuration\ndocker:\n  registry: my-registry.com\n  username: myuser\n\nservices:\n  private-service:\n    image: my-registry.com/private-service:latest\n    # Uses global registry config\n\napps:\n  web:\n    # Per-app registry override\n    registry:\n      url: ghcr.io\n      username: different-user\n      password_secret: GITHUB_TOKEN\n    # Still uses build + transfer, registry only for pre-built images\n```\n\n---\n\n### Development Setup\n\n```bash\ngit clone https://github.com/elitan/luma\ncd luma\nbun install\nbun run dev\n```\n\n### Running Tests\n\n```bash\nbun test\n```\n\n---\n\n## 📄 License\n\nMIT License\n\n---\n\n**Made with ❤️ for developers who want simple, reliable deployments on their own infrastructure.**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felitan%2Fluma","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felitan%2Fluma","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felitan%2Fluma/lists"}