selfhost.directory

The index of self-hostable projects — ranked, categorized and served with live updates.
Own your data and stop giving it to big tech.

Cloud in a Bottle logo

Self-host Cloud in a Bottle

v0.3.0

Personal PaaS for apps you own end to end

BetaOpen SourceAGPL-3.0
Updated9 hours ago
LanguagePython
Setup difficultyAdvanced
Stars
1 235
CPU
at least 1 vCPU
RAM
2 GB RAM
Storage
disk min 20GB
Ports
8080 (the router: dashboard, API and app proxying; on public deployments Caddy sits in front on 80/443), 443 (Caddy terminates TLS and reverse-proxies to the router (standard public deployment)), 80 (Caddy permanently redirects HTTP to HTTPS), 53 (CoreDNS, the instance's authoritative nameserver for the delegated zone (TCP+UDP))
Requires
rootless Podman, Ubuntu
Install with Debian
Instance dashboard showing a variety of installed apps

What is Cloud in a Bottle?

Should you self-host Cloud in a Bottle?

Cloud in a Bottle scores 51/100 on selfhost.directory (how scoring works) and ranks #9 of 10 in PaaS. It has 1 235 GitHub stars.

It shipped 7 stable releases in the past year. The latest, v0.3.0, came out on 26 October 2026. New versions land roughly every 3 weeks.

Setup is advanced: plan for several services and some ongoing maintenance. It is AGPL-3.0-licensed and written mostly in Python.

Its closest alternative on selfhost.directory is Openship (67/100, 14 966 stars). It scores higher overall, so compare the two before you pick. See Cloud in a Bottle vs Openship side by side.

Features

  • Automatic HTTPS certificates
  • Browser Terminal
  • Built for AI agents
  • CLI Client
  • Cross-app service APIs
  • Deploy apps from Git repositories
  • Encrypted backupsmust be configured before it creates snapshots; archive data is excluded
  • Migration between instancestemporary and archive data are not migrated
  • One-click app catalog
  • Owner-only access with public pathsper-person logins are not available yet
  • Rootless container sandboxing
  • Self-updating instances
  • Subdomain routing per app
  • Tiered app storage
  • Web dashboard for app management

Cloud in a Bottle README

How to install Cloud in a Bottle

Install Cloud in a Bottle with Debian

For a cloud instance with a static public IPv4. A dedicated home machine uses the same script pointed at a local HTTP domain.

How to configure Cloud in a Bottle

  • access_all_app_datafalsemanifest [data] table: mount all apps' permanent, temporary and archive data read-write under /data, for admin/file-browser/backup apps

    manifest [data] table: mount all apps' permanent, temporary and archive data read-write under /data, for admin/file-browser/backup apps

  • acme_account_key_pathpath to your own ACME account key, used to talk to the certificate authority directly

    path to your own ACME account key, used to talk to the certificate authority directly

  • acme_directory_urlLet's EncryptACME directory URL of the certificate authority

    ACME directory URL of the certificate authority

  • acme_emailemail registered with the ACME account (installer flag --acme-email)

    email registered with the ACME account (installer flag --acme-email)

  • app_archivefalsemanifest [data] table: provision a directory in archive storage (local disk or remote S3), exposed via BOTTLE_APP_ARCHIVE_DIR

    manifest [data] table: provision a directory in archive storage (local disk or remote S3), exposed via BOTTLE_APP_ARCHIVE_DIR

  • app_datatruemanifest [data] table: provision a permanent app data directory, exposed via BOTTLE_APP_DATA_DIR

    manifest [data] table: provision a permanent app data directory, exposed via BOTTLE_APP_DATA_DIR

  • app_temp_datafalsemanifest [data] table: provision an ephemeral data directory, exposed via BOTTLE_APP_TEMP_DIR

    manifest [data] table: provision an ephemeral data directory, exposed via BOTTLE_APP_TEMP_DIR

  • authorsmanifest [app] table: list of author names (optional)

    manifest [app] table: list of author names (optional)

  • AWS_ACCESS_KEY_IDbackup backend credential entered in the backup app for S3-style storage

    backup backend credential entered in the backup app for S3-style storage

  • AWS_SECRET_ACCESS_KEYbackup backend credential entered in the backup app for S3-style storage

    backup backend credential entered in the backup app for S3-style storage

  • BOTTLE_APP_ARCHIVE_DIRenvironment variable exposing the app's archive storage directory

    environment variable exposing the app's archive storage directory

  • BOTTLE_APP_DATA_DIRenvironment variable exposing the app's permanent data directory

    environment variable exposing the app's permanent data directory

  • BOTTLE_APP_TEMP_DIRenvironment variable exposing the app's temporary data directory

    environment variable exposing the app's temporary data directory

  • BOTTLE_APP_TOKENper-app token injected into each container, used to authenticate cross-app service calls

    per-app token injected into each container, used to authenticate cross-app service calls

  • BOTTLE_ROUTER_URLURL of the router, used by apps to call cross-app services

    URL of the router, used by apps to call cross-app services

  • BOTTLE_SQLITE_<NAME>environment variable exposing each provisioned SQLite database

    environment variable exposing each provisioned SQLite database

  • build_memory_mbmanifest [resources] table: memory limit in MB for the image build step; defaults to the app's memory_mb

    manifest [resources] table: memory limit in MB for the image build step; defaults to the app's memory_mb

  • cloudinabottle.tomlmanifest file at the root of an app repo declaring how the app is deployed

    manifest file at the root of an app repo declaring how the app is deployed

  • commandmanifest [runtime.container] table: override the container CMD

    manifest [runtime.container] table: override the container CMD

  • config.tomlinstance configuration file, at <data dir>/config.toml

    instance configuration file, at <data dir>/config.toml

  • container_portmanifest [[ports]] entry: port inside the container (required)

    manifest [[ports]] entry: port inside the container (required)

  • cpu_cores0.1manifest [resources] table: CPU allocation in cores (1.0 = 1 core)

    manifest [resources] table: CPU allocation in cores (1.0 = 1 core)

  • data_root_dirconfig.toml key naming the single data directory the instance keeps everything under

    config.toml key naming the single data directory the instance keeps everything under

  • descriptionmanifest [app] table: short description of the app (optional)

    manifest [app] table: short description of the app (optional)

  • --domaininstaller flag: the domain the instance serves

    installer flag: the domain the instance serves

  • health_checkmanifest [routing] table: health check path used to determine when the app has finished booting

    manifest [routing] table: health check path used to determine when the app has finished booting

  • host_port0manifest [[ports]] entry: port on the host; 0 auto-assigns from the 9000-9999 range, ports 80/443 are reserved by the router

    manifest [[ports]] entry: port on the host; 0 auto-assigns from the 9000-9999 range, ports 80/443 are reserved by the router

  • imagemanifest [runtime.container] table: path to Dockerfile relative to repo root (required)

    manifest [runtime.container] table: path to Dockerfile relative to repo root (required)

  • labelmanifest [[ports]] entry: unique label for this port mapping (required)

    manifest [[ports]] entry: unique label for this port mapping (required)

  • --local-http-onlyinstaller flag for a plain-HTTP local-only install

    installer flag for a plain-HTTP local-only install

  • memory_mb128manifest [resources] table: max container memory in MB

    manifest [resources] table: max container memory in MB

  • --open-claiminstaller flag used on private local installs

    installer flag used on private local installs

  • portmanifest [runtime.container] table: port the app responds to HTTP on (required)

    manifest [runtime.container] table: port the app responds to HTTP on (required)

  • start_caddyset false on HTTP-only installs so no Caddy starts and the router serves :8080 directly

    set false on HTTP-only installs so no Caddy starts and the router serves :8080 directly

    values: true / false

  • versionmanifest [app] table: version string; conventionally semver, but only checked for non-emptiness

    manifest [app] table: version string; conventionally semver, but only checked for non-emptiness

Cloud in a Bottle releases & version history

More in PaaS

Rate this project

Click to rate — no account needed.

0 comments

Posting as guest
Loading comments…