{"id":31701714,"url":"https://github.com/getlantern/unbounded","last_synced_at":"2026-05-03T00:04:35.460Z","repository":{"id":226656623,"uuid":"563419589","full_name":"getlantern/unbounded","owner":"getlantern","description":"Next-gen P2P proxies for censorship circumvention","archived":false,"fork":false,"pushed_at":"2025-09-29T23:20:48.000Z","size":187310,"stargazers_count":34,"open_issues_count":78,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-09-30T01:15:52.131Z","etag":null,"topics":["censorship-circumvention","p2p","proxy","wasm"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/getlantern.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-11-08T15:18:10.000Z","updated_at":"2025-09-29T23:20:52.000Z","dependencies_parsed_at":"2024-05-02T17:45:40.136Z","dependency_job_id":"89788032-c118-4006-9a94-c6f2c797fcd7","html_url":"https://github.com/getlantern/unbounded","commit_stats":null,"previous_names":["getlantern/broflake","getlantern/browsersunbounded","getlantern/unbounded"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/getlantern/unbounded","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getlantern%2Funbounded","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getlantern%2Funbounded/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getlantern%2Funbounded/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getlantern%2Funbounded/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getlantern","download_url":"https://codeload.github.com/getlantern/unbounded/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getlantern%2Funbounded/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000716,"owners_count":26082837,"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","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["censorship-circumvention","p2p","proxy","wasm"],"created_at":"2025-10-08T21:07:43.172Z","updated_at":"2026-04-23T06:03:22.153Z","avatar_url":"https://github.com/getlantern.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"```\n             _                           _          _ \n            | |                         | |        | |\n _   _ _ __ | |__   ___  _   _ _ __   __| | ___  __| |\n| | | | '_ \\| '_ \\ / _ \\| | | | '_ \\ / _` |/ _ \\/ _` |\n| |_| | | | | |_) | (_) | |_| | | | | (_| |  __/ (_| |\n \\__,_|_| |_|_.__/ \\___/ \\__,_|_| |_|\\__,_|\\___|\\__,_|\n```\n\n# :compass: Table of contents\n* [What is Unbounded?](#question-what-is-unbounded)\n* [Features](#boom-features)\n* [Related work](#love_letter-related-work)\n* [System components](#floppy_disk-system-components)\n* [Quickstart for devs](#arrow_forward-quickstart-for-devs)\n* [Observing networks with netstate](#spider_web)\n* [UI](#art-ui)\n\n### :question: What is Unbounded?\nUnbounded is a next-gen technology stack for circumventing internet censorship using browser-based \nP2P proxies. It organizes an ephemeral swarm of short-lived residential IP addresses, provided by volunteers in less censored regions, which create censorship resistant routes for network requests originating from users in heavily censored regions.\n\n**Here are just a few of the things you can do:**\n\n* Turn your friends into a private swarm to unblock a loved one in a censored region ([tutorial](https://github.com/getlantern/unbounded/blob/main/examples/private-swarm)) :fire:\n* Add a P2P transport to your circumvention app (tutorial coming soon)\n* Volunteer on the Lantern network with just one click ([link](https://unbounded.lantern.io))\n* Add the Lantern volunteer widget to your website (tutorial coming soon)\n* Deploy a permanent volunteer node on a Raspberry Pi (tutorial coming soon)\n\n### :boom: Features\n* End-to-end connection state persistence across ephemeral peer transports\n* HTTP and SOCKS5 mode\n* Concurrent client for IP efficiency: 1 volunteer can proxy for N users simultaneously\n* N:M multiplexing\n* High performance, low latency, rapid peer discovery\n* Maintainable and debuggable: one cross-platform WebAssembly-friendly engine that runs everywhere\n\n### :love_letter: Related work\nUnbounded is a descendant of the \"flash proxy\" concept first described in 2012 by David Fifield,\nNate Hardison, Jonathan Ellithorpe, Emily Stark, Dan Boneh, Roger Dingledine, and Phil Porras \n([paper](https://crypto.stanford.edu/flashproxy/flashproxy.pdf)).\n\n[uProxy](https://en.wikipedia.org/wiki/UProxy) is a historical project exploring similar \nideas that also started in 2012 as a collaboration between Google Ideas (now Jigsaw), the University of Washington,\nand the Brave New Software Project, the creators of [Lantern](https://lantern.io).\n\n[Snowflake](https://snowflake.torproject.org/), part of the Tor project, is an evolution of the same concenpt, with\nroots in both flash proxy and uProxy, and it is widely used today.\n\nThe idea to create connection state persistence across ephemeral peer transports was formalized \nby David Fifield as \"Turbo Tunnel\" in 2020 ([paper](https://www.bamsoftware.com/papers/turbotunnel/turbotunnel.pdf)).\n\n### :floppy_disk: System components\n![system](https://user-images.githubusercontent.com/21117002/176231832-1c558546-8933-4e25-b8df-f60edb4ed6d5.png)\n\n| Module     | Description                                                                                   |\n|------------|-----------------------------------------------------------------------------------------------|\n| clientcore | library exposing Unbounded's high level client API                                            |\n| cmd        | driver code for operationalizing Unbounded outside of a controlling process                   |\n| common     | data structures and functionality shared across Unbounded modules                             |\n| egress     | egress server                                                                                 |\n| freddie    | discovery, signaling, and matchmaking server                                                  |\n| netstate   | network topology observability tool                                                           |\n| ui         | embeddable web user interface          \n\n\u003cimg width=\"981\" alt=\"image\" src=\"https://github.com/getlantern/browsersunbounded/assets/1143966/4de8bc34-5ed9-4029-93d2-51c0691a5077\"\u003e   \n\n### :arrow_forward: Quickstart for devs\n1. Clone this repo.\n\n2. Configure **Mozilla Firefox** to use a local HTTP proxy. In settings, search \"proxy\". Select \n*Manual proxy configuration*. Enter address `127.0.0.1`, port `1080`, and check the box labeled \n*Also use this proxy for HTTPS*.\n\n3. Build the native binary desktop client: `cd cmd \u0026\u0026 ./build.sh desktop`\n\n4. Build the native binary widget: `cd cmd \u0026\u0026 ./build.sh widget`\n\n5. Build the browser widget: `cd cmd \u0026\u0026 ./build_web.sh`\n\n6. Start Freddie: `cd freddie/cmd \u0026\u0026 PORT=9000 go run main.go`\n\n7. Start the egress server: `cd egress/cmd \u0026\u0026 PORT=8000 go run egress.go`\n\n8. Start a desktop client: `cd cmd/dist/bin \u0026\u0026 FREDDIE=http://localhost:9000 \nEGRESS=http://localhost:8000 ./desktop`\n\n9. Decision point: do you want to run a **native binary** widget or a **browser** widget? To start \na native binary widget: `cd cmd/dist/bin \u0026\u0026 FREDDIE=http://localhost:9000 EGRESS=http://localhost:8000 \n./widget`. Alternatively, to start a browser widget, follow the \n[UI quickstart](#ui-quickstart-for-devs).\n\n_The widget and desktop client find each other via the discovery server, execute a signaling step,\nand establish several WebRTC connections._\n\n10. Start **Mozilla Firefox**. Use the browser as you normally would, visiting all your favorite\nwebsites. Your traffic is proxied in a chain: Firefox -\u003e local HTTP proxy -\u003e desktop client -\u003e \nwebRTC -\u003e widget -\u003e WebSocket -\u003e egress server -\u003e remote HTTP proxy -\u003e the internet. \n\n### :spider_web: Observing networks with netstate\nThe netstate module is a work-in-progress tool for observing Unbounded networks. netstate currently \nvisualizes network topology, labeling each Unbounded node with an arbitrary, user-defined \"tag\" which\nmay be injected at runtime.\n\n`netstated` is a distributed state machine which collects and processes state changes from Unbounded\nclients. It serves a network visualization at `GET /`. The `gv` visualizer client looks for a \n`netstated` instance at `localhost:8080`.\n\nIn the example below, we assume that Freddie is at `http://localhost:9000` and the egress server\nis at `http://localhost:8000`:\n\n1. Start `netstated`: `cd netstate/d \u0026\u0026 go run netstated.go`\n\n2. Start a widget as user Alice: `cd cmd/dist/bin \u0026\u0026 NETSTATED=http://localhost:8080/exec TAG=Alice\nFREDDIE=http://localhost:9000 EGRESS=http://localhost:8000 ./widget`\n\n3. Start a desktop client as user Bob: `cd cmd/dist/bin \u0026\u0026 NETSTATED=http://localhost:8080/exec \nTAG=Bob FREDDIE=http://localhost:9000 EGRESS=http://localhost:8000 ./desktop`\n\n4. Open a web browser and navigate to `http://localhost:8080`. As Alice and Bob complete the \nsignaling process and establish connection(s) to one another, you should see the network you have\ncreated. You must refresh the page to update the visualization.\n\n### :art: UI\n\n![ui system](https://user-images.githubusercontent.com/24487544/220998573-0b1f3bd2-66d1-41eb-b256-4da1aa69da76.png)\n\n#### UI settings and configuration\n\nThe UI is bootstrapped with [Create React App](https://github.com/facebook/create-react-app). Then \"re-wired\" to build one single js bundle entry using [rewire](https://www.npmjs.com/package/rewire). \nThe React app will bind to a custom `\u003cbrowsers-unbounded\u003e` DOM el and render based on settings passed to the [dataset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset). \nIn development, this html can be found in `ui/public/index.html`. In production, the html is supplied by the \"embedder\" via https://unbounded.lantern.io/embed.\n\nExample production embed:\n\n```html\n\u003cbrowsers-unbounded\n   data-layout=\"banner\"\n   data-theme=\"dark\"\n   data-globe=\"true\"\n   data-exit=\"true\"\n   style='width: 100%;'\n\u003e\u003c/browsers-unbounded\u003e\n\u003cscript defer=\"defer\" src=\"https://embed.lantern.io/static/js/main.js\"\u003e\u003c/script\u003e\n```\n\nThis tables lists all the available settings that can be passed to the `\u003cbrowsers-unbounded\u003e` DOM el via the `data-*` attributes. \nThe \"default\" column shows the default value if the attribute is not set.\n\n| dataset   | description                                               | default |\n|-----------|-----------------------------------------------------------|---------|\n| layout    | string \"banner\" or \"panel\" layout                         | banner  |\n| theme     | string \"dark\", \"light\" or \"auto\" (browser settings) theme | light   |\n| globe     | boolean to include webgl globe                            | true    |\n| exit      | boolean to include toast on exit intent                   | true    |\n| menu      | boolean to include menu                                   | true    |\n| keep-text | boolean to include text to keep tab open                  | true    |\n| mobile-bg | boolean to run on mobile background                       | false   |\n| mobile-bg | boolean to run on desktop background                      | true    |\n| editor    | boolean to include debug dataset editor                   | false   |\n| branding  | boolean to include logos                                  | true    |\n| mock      | boolean to use the mock wasm client data                  | false   |\n| target    | string \"web\", \"extension-offscreen\" or \"extension-popup\"  | web     |\n\nIn development, these settings can be customized using the `REACT_APP_*` environment variables in the `.env` or in your terminal.\nFor example, to run the widget in \"panel\" layout, you can run `REACT_APP_LAYOUT=panel yarn start`. To run the widget with mock data,\nyou can run `REACT_APP_MOCK=true yarn start`. \n\nSettings can also be passed to the widget via the `data-*` attributes in `ui/public/index.html`. For example, to run the widget in \"panel\" layout,\nyou can set `data-layout=\"panel\"` in `ui/public/index.html`.\n\nIf you enable the editor (by setting `REACT_APP_EDITOR=true` or `data-editor=\"true\"`), you can also edit the settings dynamically in the browser using a UI editor the renders above the widget.\n*Note* that the `mock` and `target` settings are not dynamic and therefore not editable in the browser. These two settings are static and must be set at the time the wasm interface is initialized.\n\nLinks:\n\n[Github pages sandbox](https://embed.lantern.io)\n\n[Unbounded website](https://unbounded.lantern.io)\n\n#### UI quickstart for devs\n\n1. Work from the ui dir: `cd ui`\n2. Install deps: `yarn`\n\nDevelopment:\n1. Copy the example env: `cp .env.development.example .env.development`\n2. Start the dev server: `yarn dev:web` and open [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nProduction:\n1. Copy the example env: `cp .env.production.example .env.production`\n2. Build and deploy prod bundle to Github page: `yarn deploy`\n\n#### UI deep dive for devs\n\n1. Work from the ui dir: `cd ui`\n\n2. Configure your .env file: `cp .env.development.example .env.development` \n   1. Set `REACT_APP_WIDGET_WASM_URL` to your intended hosted `widget.wasm` file. If you are serving it from `client` in [step #8](#arrow_forward-quickstart-for-devs), use [http://localhost:9000/widget.wasm](http://localhost:9000/widget.wasm). If you ran `./build_web.sh` ([step #7](#arrow_forward-quickstart-for-devs)) you can also use `/widget.wasm`. To config for prod point to a publicly hosted `widget.wasm` e.g. `https://embed.lantern.io/widget.wasm`. If you know you know, if not, you likely want to use `/widget.wasm`.\n   2. Set `REACT_APP_GEO_LOOKUP_URL` to your intended geo lookup service. Most likely `https://geo.getiantem.org/lookup` or `http://localhost:\u003cPORT\u003e/lookup` if testing geo lookups locally\n   3. Set `REACT_APP_STORAGE_URL` to your intended iframe html for local storage of widget state and analytics. Most likely `https://embed.lantern.io/storage.html` or `/storage.html` if testing locally\n   4. Set any `REACT_APP_*` variables as needed for your development environment. See [UI settings and configuration](#ui-settings-and-configuration) for more info.\n   5. Configure the WASM client endpoints: `REACT_APP_DISCOVERY_SRV`, `REACT_APP_DISCOVERY_ENDPOINT`, `REACT_APP_EGRESS_ADDR` \u0026 `REACT_APP_EGRESS_ENDPOINT`\n   6. Configure the CMS and translations: `STRAPI_API_TOKEN` \u0026 `STRAPI_API_URL`\n\n3. Install the dependencies: `yarn`\n\n4. To start in developer mode with hot-refresh server (degraded performance): run `yarn dev:web` and visit [http://localhost:3000](http://localhost:3000)\n\n5. To build optimized for best performance: \n   1. First configure your .env file: `cp .env.production.example .env.production` (see Step 2)\n   2. Run `yarn build:web`\n\n6. To serve a build:\n   1. Install a simple server e.g. `npm install -g serve` (or your lightweight http server of choice)\n   2. Serve the build dir e.g. `cd build \u0026\u0026 serve -s -l 3000` and visit [http://localhost:3000](http://localhost:3000)\n\n7. To deploy to Github pages: `yarn deploy`\n\n8. Coming soon to a repo near you: `yarn test`\n\n#### Browser extension quickstart for devs\n\n1. Work from the ui dir: `cd ui`\n\n2. Install the dependencies: `yarn`\n\n3. Configure your .env file: `cd extension \u0026\u0026 cp .env.example .env`\n   1. Set `EXTENSION_POPUP_URL` to your intended hosted popup page. If you are serving it from `ui` in [step #6](#ui-quickstart-for-devs), use [http://localhost:3000/popup](http://localhost:3000/popup). To use prod, set to [https://embed.lantern.io/popup](https://embed.lantern.io/popup).\n   2. Set `EXTENSION_OFFSCREEN_URL` to your intended hosted offscreen page. If you are serving it from `ui` in [step #6](#ui-quickstart-for-devs), use [http://localhost:3000/offscreen](http://localhost:3000/offscreen). To use prod, set to [https://embed.lantern.io/offscreen](https://embed.lantern.io/offscreen).\n\n3. To start in developer mode with hot-refresh server:\n```\nyarn dev:ext chrome\nyarn dev:ext firefox \n```\n\nThis will compile the extension and output to the `ui/extension/dist` dir. You can then load the unpacked extension in your browser of choice. \n- For Chrome, go to [chrome://extensions](chrome://extensions) and click \"Load unpacked\" and select the `ui/extension/dist/chrome` dir. \n- For Firefox, go to [about:debugging#/runtime/this-firefox](about:debugging#/runtime/this-firefox) and click \"Load Temporary Add-on\" and select the `ui/extension/dist/firefox/manifest.json` file. \n- For Edge, go to [edge://extensions](edge://extensions) and click \"Load unpacked\" and select the `ui/extension/dist/edge` dir.\n\n4. To build for production:\n```\nyarn build:ext chrome\nyarn build:ext firefox \n```\n\nThis will compile the extension and output a compressed build to the `ui/extension/packages` dir. \n\n### CMS \u0026 Translations\n\nThe copy and translations are bootstrapped with [Strapi](https://strapi.io/) as a headless CMS to manage translations and other content for the UI.\n\nThe translations are queried at build time and the UI uses the `i18next` library to manage the translations and the `react-i18next` library to bind the translations to the UI components.\n\nTo re-query the translations from the CMS, run `yarn translate`. This will fetch the latest translations from the CMS and update the `src/translations.json` file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetlantern%2Funbounded","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetlantern%2Funbounded","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetlantern%2Funbounded/lists"}