{"id":28727423,"url":"https://github.com/monorkin/twice","last_synced_at":"2025-07-27T02:02:54.398Z","repository":{"id":293666173,"uuid":"980566008","full_name":"monorkin/twice","owner":"monorkin","description":"A clone of the Once distribution system - a license key based distribution system for Docker containers.","archived":false,"fork":false,"pushed_at":"2025-05-20T07:28:24.000Z","size":195,"stargazers_count":27,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-08T11:49:31.613Z","etag":null,"topics":["distribution-system","docker","rails"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/monorkin.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-09T10:41:25.000Z","updated_at":"2025-06-04T07:19:33.000Z","dependencies_parsed_at":"2025-05-16T14:39:19.691Z","dependency_job_id":"3888ca0f-2e54-40be-80d5-b8a0d43f4469","html_url":"https://github.com/monorkin/twice","commit_stats":null,"previous_names":["monorkin/twice"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/monorkin/twice","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monorkin%2Ftwice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monorkin%2Ftwice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monorkin%2Ftwice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monorkin%2Ftwice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/monorkin","download_url":"https://codeload.github.com/monorkin/twice/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monorkin%2Ftwice/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259991299,"owners_count":22942611,"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":["distribution-system","docker","rails"],"created_at":"2025-06-15T14:39:41.873Z","updated_at":"2025-06-15T14:39:45.326Z","avatar_url":"https://github.com/monorkin.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# Twice\n\nTwice is a clone of the [Once](https://once.com) distribution system \nused by [Campfire](https://once.com/campfire) and [Writebook](https://once.com/writebook).\n\nThrough Twice you can generate and distribute license keys with which\nusers can install and run Docker containers of your products on their own servers.\n\n## About\n\nTwice gives you the ability to issue license keys\nthat can be used to install a product.\n\nProducts are Docker containers installed from Docker images hosted on a \nprivate Docker Registry.\n\nThe whole installation process looks like this:\n\n```bash\n# Download and install the Twice CLI,\n# and then install a product with the license key nx1w-qg52-e5t3-kpa4 from auth.example.com\n/bin/bash -c \"$(curl -fsSL http://auth.example.com/install/nx1w-qg52-e5t3-kpa4)\"\n\n# Install a product with the license key nx1w-qg52-e5t3-kpa4 from example.org\ntwice setup nx1w-qg52-e5t3-kpa4@example.org\n✅ Docker is installed\n✅ Docker is running\n✅ License is valid\n   ├──Auth server: example.org\n   ├──License key: nx1w-qg52-e5t3-kpa4\n   ├──License owner: kaladin.stormblessed@example.com\n   └──Product: Sphere Sorter\n✅ Product added to the config\n✅ App downloaded\nEnter the domain (e.g. example.com) where you\\'ll run the app: example.com\nDo you want to enable HTTPS? (YES/no): yes\n   ├──Domain: example.com\n   └──HTTPS: true\nIs this correct? (yes/NO): yes\n✅ Product config saved\n✅ App is running\n\ncurl -H \"Host: example.com\" https://localhost/up\nOK\n\ntwice status\n┌────────────────────────┬───────────────┬─────────────────────┬────────────────┬─────────┐\n│           ID           │    PRODUCT    │       LICENSE       │  AUTH SERVER   │ STATUS  │\n├────────────────────────┼───────────────┼─────────────────────┼────────────────┼─────────┤\n│ sphere-sorter-580e3812 │ Sphere Sorter │ nx1w-qg52-e5t3-kpa4 │  example.org   │ Running │\n└────────────────────────┴───────────────┴─────────────────────┴────────────────┴─────────┘\n\ntwice stop sphere-sorter-580e3812\n✅ Product stopped\n\ntwice status\n┌────────────────────────┬───────────────┬─────────────────────┬────────────────┬─────────┐\n│           ID           │    PRODUCT    │       LICENSE       │  AUTH SERVER   │ STATUS  │\n├────────────────────────┼───────────────┼─────────────────────┼────────────────┼─────────┤\n│ sphere-sorter-580e3812 │ Sphere Sorter │ nx1w-qg52-e5t3-kpa4 │  example.org   │ Stopped │\n└────────────────────────┴───────────────┴─────────────────────┴────────────────┴─────────┘\n```\n\nYou can distribute one or more products this way, and even copies of the same product.\n\nA detailed explanation of how all of this works, and how Twice came to be, can be found [here](https://stanko.io/building-twice-a-clone-of-once-gJKxLYCe26Ak).\n[Release 0.1.0](https://github.com/monorkin/twice/releases/tag/0.1.0) contains all the code referenced in that article.\n\n## Repo organization\nThis is a mono-repo that contains 3 projects:\n1. Auth\n2. CLI\n3. Registry\n\n**Auth** handles 3 tasks - it provides installation scripts and binaries, it is the \nauth backend for the Registry, and it manages products and license keys.\n\n**CLI** installs a product associated with a given license key and manages all installed products.\n\n**Registry** is a Docker Registry that hosts app images for products.\n\n## Development\n\n**First**, make sure you have the following installed:\n1. Ruby 3.4 or newer\n2. Go 1.23 or newer\n3. Docker\n4. Docker Compose\n\n**Second**, from the root of the project run `bin/setup`.\n\nThis will setup the Registry and the Auth server so that they can talk to one another.\nAnd it will compile the CLI, and prepare it to be distributed using the Auth server.\n\n**Third**, in a separate terminal window, from the `registry` directory,\nrun `docker compose up` to start the registry.\n\nCheck out the docker-compose.yml file to see how the registry is configured, and \nchange it for your OS.\n\n**Fourth**, in another terminal window from the `auth` directory run:\n\n```bash\nbundle\nbin/rails db:create db:migrate db:fixtures:load\nbin/dev\n```\n\nThis will install all the necessary dependencies, create the database, run the migrations,\nand then start the server on [localhost:3000](http://localhost:3000).\n\n## Usage\n\n### Auth\nYou can login with any Developer account to the Auth UI.\n\nOut-of-the-box there are several accounts already pre-populated\n(if you've run bin/rails `db:fixtures:load`). You can take a look\nat [developers.yml](auth/db/fixtures/developers.yml) to see which\naccounts exists and what their credentials are.\n\nIn the UI you can create products, developers, customers, and\npurchase licenses for customers.\n\nYou can also install a product directly from the auth server using this command:\n\n```bash\n/bin/bash -c \"$(curl -fsSL http://localhost:3000/install/nx1w-qg52-e5t3-kpa4)\"\n```\n\nThis will download and install the cli binary, and then run it, passing it\nthe license key from the URL.\n\n### Registry\n\nUsing the same credentials you can login to the Registry and\npush any Docker image you like to it.\n\nJust note that only developer accounts have push access to the registry\n\n```bash\ndocker login --username jezrien@example.com --password password http://localhost:5000\n\ndocker pull hello-world\ndocker tag hello-world http://localhost:5000/hello-world\n\ndocker push http://localhost:5000/hello-world\n```\n\nTo delete images from the registry you can use\n\n```bash\nbin/delete-image localhost:5000 hello-world jezrien@example.com password\n```\n\n### CLI\n\nTo install a product using the CLI you have to run the following command from the `cli` directory:\n\n```bash\ngo run cmd/twice/main.go setup \u003clicense-key\u003e\n# e.g. `go run cmd/twice/main.go setup nx1w-qg52-e5t3-kpa4`\n```\n\nThis will pull the product's Docker image from the registry and spin up a container for it\n## Uninstall\n\nTo uninstall the CLI run\n\n```bash\nrm /usr/local/bin/twice\n```\n\nThat's it.\n\n## License\n\nThis project is licensed under the [MIT License](./LICENSE), you can read the full license [here](./LICENSE).\n\nLong story short, you can do whatever you want with this code, as long as you include\nthe original, unchanged, license of this project in your project and give proper attribution.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonorkin%2Ftwice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmonorkin%2Ftwice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonorkin%2Ftwice/lists"}