{"id":16842323,"url":"https://github.com/dgtlmoon/lemonade-fresh","last_synced_at":"2025-04-10T13:14:59.397Z","repository":{"id":139298581,"uuid":"454171141","full_name":"dgtlmoon/lemonade-fresh","owner":"dgtlmoon","description":"Lemonade Fresh - Cryptocurrency Paid Container Provisioner","archived":false,"fork":false,"pushed_at":"2022-02-02T13:26:14.000Z","size":1794,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-24T12:03:38.448Z","etag":null,"topics":["bitcoin","containers","crypto","cryptocurrency","docker","docker-compose","python","self-hosted","web"],"latest_commit_sha":null,"homepage":"","language":"Python","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/dgtlmoon.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}},"created_at":"2022-01-31T21:10:24.000Z","updated_at":"2024-11-25T18:08:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"fe7236f9-17cc-49cb-b74b-24fbb79593f9","html_url":"https://github.com/dgtlmoon/lemonade-fresh","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgtlmoon%2Flemonade-fresh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgtlmoon%2Flemonade-fresh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgtlmoon%2Flemonade-fresh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgtlmoon%2Flemonade-fresh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dgtlmoon","download_url":"https://codeload.github.com/dgtlmoon/lemonade-fresh/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248225650,"owners_count":21068078,"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":["bitcoin","containers","crypto","cryptocurrency","docker","docker-compose","python","self-hosted","web"],"created_at":"2024-10-13T12:45:24.595Z","updated_at":"2025-04-10T13:14:59.178Z","avatar_url":"https://github.com/dgtlmoon.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg width=256 src=\"https://raw.githubusercontent.com/dgtlmoon/lemonade-fresh/main/app/static/images/blue-thunder-p7-lemonadestand-expand.jpg\"\u003e\n\n# Lemonade Fresh - Cryptocurrency Paid Container Provisioner\n\nAn extremely simple platform which enables you to host a docker container in exchange for digital currency (bitcoin/litecoin/dogecoin)\n\n*In otherwords* - provision a container using docker-compose when someone pays you with cryptocurrency - host that container for them, accessible as a URL path on your server (that URL path is automatically generated from two random words)\n\n_Yes I'm sure there's a better way todo this, but this works for me :), and it was the fastest way I could get some proof of concept working_\n\n\u003cimg src=\"https://raw.githubusercontent.com/dgtlmoon/lemonade-fresh/main/screenshot.png?large=ok\"\u003e\n\n# How does it work?\n\n- A person who is interested registers via a simple flask application, the application creates a cryptocurrency payment address, this is emailed and presented to them.\n- When a correct payment is detected, a `data/docker-compose-paid-instances.yml` is re-generated with the paid container information (and a container name which is also the container hostname), managed by a simple SQLite DB\n- `docker-compose up` runs periodically, it knows when a YAML has changed thanks to its internal checksums, so lazy so implementation.. \n- The new paid container is running, and has a randomly generated hostname, this hostname is available as http://yoursite/random-name via `proxy_pass`\n\nThen the new 'customer' simply accesses their hosted container via nginx's `proxy_pass` as a path on your server, it's recommended to run the containers as a sub-domain, otherwise the nginx rules get a bit complicated ie, https://pay-me.mydomain.io/ , so the hosted container would be available as https://pay-me.mydomain.io/random-name\n\n\nSome extra bonus stuff happens like\n- Generate a salted password and set it as an ENV var so they can login\n- [volumes are also created in the docker-compose YAML generator](https://github.com/dgtlmoon/lemonade-fresh/blob/b3d737100c2e94f895c53f7f88b7937a1c3a03e2/app/dcgenerator.py#L30)\n\n\n# Syncing new containers when paid\n\n```\n# m h  dom mon dow   command\n*/2 * * * * curl -s https://your-site.com/sync \u003e/dev/null \u0026\u0026 cd /var/www/provisioner \u0026\u0026 docker-compose --log-level=WARNING -f docker-compose.yml -f docker-compose.prod.yml -f data/docker-compose-paid-instances.yml  up -d --remove-orphans\n```\n\nThere's some **very lazy** things going on here\n- Runs every 2 minutes\n- `docker-compose.yml` the stock one, required\n- `docker-compose.prod.yml` your local settings, like setting the crypto network (`bitcoin`/`testnet`/`litecoin` etc) and return coin address\n- `data/docker-compose-paid-instances.yml` the generated extra docker-compose YAML for paid instances\n\nThe lazy magic here, is that docker-compose wont do anything unless one of the YAML's change, `up` supports `--remove-orphans` so it's easy to remove containers that are not paid for, and `--log-level=WARNING` keeps it quiet unless something bad happens.\n\nThe only shameful thing is that `/sync` call, which re-builds the composer and checks for payments, your nginx shouldnt allow this to be accessed other than locally (or change the code and move it to a local command)\n\nProbably nearly all of this can be removed by using an actual decent interface like coinbase's API, which handles payments way better, but, where is the fun in that? :)\n\n\nSo basically, when someone has paid for their container, a random name is generated (`stir-commuted` herein), and `data/docker-compose-paid-instances.yml` will contain for example...\n\n```\n  paid_instance_stir-commuted:\n    image: dgtlmoon/changedetection.io:latest\n    networks:\n    - provisioner_net\n    environment:\n    - USE_X_SETTINGS=1\n    - SALTED_PASS=abc123\n    hostname: stir-commuted\n    volumes:\n    - paid_instance_stir-commuted-data:/datastore\n    restart: unless-stopped\n\n```\n\nAnd they can access it via https://yoursite.com/stir-commuted via [this nginx location statement](https://github.com/dgtlmoon/lemonade-fresh/blob/2c2443601a53e14007aca0185320b71e00d59bdd/config/nginx/default.conf#L32)\n\n`image:` is set by `HOSTED_IMAGE` env var\n\nOnce it is paid, the server will send the coin balance onto an another address, which should NOT be on the server\n\n## Testing/Development\n\n- I like the [Electrum client](https://electrum.org/), start it in _testnet_ mode, `electrum --testnet`\n- Use https://testnet-faucet.com/btc-testnet/ or a similar \"test coin faucet\" to get some test-coins (remember to return them when you're done!)\n- It's good to set the return address for the coins back to your wallet (dont store them on the server! See `BTC_FORWARD_ADDRESS` env var)\n\n## Batteries NOT included\n\n- Some web-ops stuff like `certbot` not included, you will need to sort out how this works.\n- No threaded python gunicorn etc server\n\n## Going forwards\n- You could use a wildcard DNS entry, tweak the nginx rules, and bounce the requests to a `random-name.yoursite.com` instead of a path suffix, then you dont have to worry about mapping paths etc and they could enjoy full socket IO access aswell\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdgtlmoon%2Flemonade-fresh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdgtlmoon%2Flemonade-fresh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdgtlmoon%2Flemonade-fresh/lists"}