{"id":30652241,"url":"https://github.com/gaetanlhf/EXPOSE","last_synced_at":"2025-08-31T07:05:48.236Z","repository":{"id":242717324,"uuid":"791821842","full_name":"gaetanlhf/EXPOSE","owner":"gaetanlhf","description":"Your no-config, no-install, globally distributed open-source tool to expose your local services","archived":false,"fork":false,"pushed_at":"2025-08-28T18:19:47.000Z","size":787,"stargazers_count":197,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-28T23:24:46.015Z","etag":null,"topics":["expose","locahost","nginx","nodejs","openresty","python","tunnel"],"latest_commit_sha":null,"homepage":"https://expose.sh","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gaetanlhf.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},"funding":{"github":"exposesh"}},"created_at":"2024-04-25T12:45:18.000Z","updated_at":"2025-08-28T18:19:50.000Z","dependencies_parsed_at":"2024-12-31T03:30:57.058Z","dependency_job_id":"b628fc72-6302-4792-a0e8-a27d50c24aef","html_url":"https://github.com/gaetanlhf/EXPOSE","commit_stats":null,"previous_names":["exposesh/expose-server","gaetanlhf/expose"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gaetanlhf/EXPOSE","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaetanlhf%2FEXPOSE","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaetanlhf%2FEXPOSE/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaetanlhf%2FEXPOSE/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaetanlhf%2FEXPOSE/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gaetanlhf","download_url":"https://codeload.github.com/gaetanlhf/EXPOSE/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaetanlhf%2FEXPOSE/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272948935,"owners_count":25020294,"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-08-31T02:00:09.071Z","response_time":79,"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":["expose","locahost","nginx","nodejs","openresty","python","tunnel"],"created_at":"2025-08-31T07:02:03.735Z","updated_at":"2025-08-31T07:05:48.227Z","avatar_url":"https://github.com/gaetanlhf.png","language":"Python","funding_links":["https://github.com/sponsors/exposesh"],"categories":["Utilities"],"sub_categories":["SSH tunnelling"],"readme":"\u003ch1 align=\"center\"\u003e\n    \u003ca href=\"https://expose.sh/#gh-light-mode-only\"\u003e\n    \u003cimg src=\"./.github/assets/expose_logo_black.svg\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://expose.sh/#gh-dark-mode-only\"\u003e\n    \u003cimg src=\"./.github/assets/expose_logo_white.svg\"\u003e\n    \u003c/a\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"#about\"\u003eAbout\u003c/a\u003e •\n    \u003ca href=\"#demo\"\u003eDemo\u003c/a\u003e •\n    \u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e •\n    \u003ca href=\"#use-cases\"\u003eUse-cases\u003c/a\u003e •\n    \u003ca href=\"#access\"\u003eAccess\u003c/a\u003e •\n    \u003ca href=\"#architecture\"\u003eArchitecture\u003c/a\u003e •\n    \u003ca href=\"#deployment\"\u003eDeployment\u003c/a\u003e •\n    \u003ca href=\"#faqs\"\u003eFAQs\u003c/a\u003e\n\u003c/p\u003e\n\n## About\n\nEXPOSE is your new favourite open source tool for exposing your local services on the public Internet with no installation or configuration required. EXPOSE relies on your SSH client and authenticates using the public SSH keys you have on your GitHub account.\n\nTo expose `localhost:3000`, simply type:\n```bash\nssh -R 1:localhost:3000 expose.sh\n```\n\nIf your computer username differs from your GitHub username:\n```bash\nssh -R 1:localhost:3000 yourusername@expose.sh\n```\n\n## Demo\n\nhttps://github.com/user-attachments/assets/9908b156-6e12-4a6e-8cf7-46b701f48461\n\n## Features\n\n- **Nothing to install**: use only your terminal and SSH client\n- **Nothing to configure**: automatically retrieve public SSH keys from your GitHub account\n- **Custom URL**: based on your GitHub username\n- **QR code generation**: for easy mobile testing\n- **Multiple tunnels**: up to 5 simultaneous services per account\n- **Distributed system**: global routing for fastest access worldwide\n- **Secure**: SSH encryption with automatic HTTPS certificates\n- **Open source**: fully transparent\n\n## Use-cases\n\n- **Demos and presentations**: access your applications from any internet-connected device\n- **Mobile development**: expose local backends for Android/iOS app testing\n- **Webhook testing**: test webhooks from payment gateways, messaging platforms, and APIs\n- **Cross-device testing**: ensure your application works on all device types\n- **Development sharing**: quickly share work-in-progress with team members\n\n## Access\n\nTo prevent malicious use, you must star this repository to access EXPOSE.  \nAuthentication is handled through your [GitHub SSH keys](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent).\n\n**Tunnel allocation:**\n- Tunnels 1-3: Named as `username`, `username-2`, `username-3`, etc.\n- Tunnels 4-5: Random names like `username-x7k2m9`\n- Maximum: 5 concurrent tunnels per user\n- Session limit: 2 hours (reconnectable unlimited times)\n\n## Architecture\n\nEXPOSE consists of three containerized components deployed globally using [Fly.io](https://fly.io):\n\n### SSH Server (Python)\n- Handles SSH connections and authentication\n- Validates GitHub SSH keys and stargazer status\n- Manages tunnel creation with slot-based naming\n- Enforces connection limits and timeouts\n- Creates Unix socket forwarding for local services\n\n### Tools Service (Node.js)\n- Acts as intermediary between SSH server and web server\n- Manages GitHub API integration with caching\n- Generates QR codes for tunnel URLs\n- Handles cache management across distributed instances\n- Serves local banner content\n\n### Web Server (OpenResty/Nginx)\n- Routes traffic to appropriate tunnels based on subdomains\n- Handles caching and load balancing\n- Provides HTTPS termination with automatic certificates\n- Manages WebSocket upgrades\n\n## Deployment\n\n### Prerequisites\n\nGenerate an SSH key pair:\n```bash\nssh-keygen -t ed25519 -f ./ssh_key -N \"\"\n```\n\n### Configuration\n\n1. Copy the example configuration:\n```bash\ncp fly.toml.example fly.toml\n```\n\n2. Update the required configuration fields:\n```toml\napp = 'your-app-name'\nprimary_region = 'cdg'  # Choose your preferred region\n\n[env]\n  FLYDOTIO_APP_NAME = 'your-app-name'\n  HTTP_URL = 'yourdomain.com'\n  SSH_SERVER_URL = 'ssh.yourdomain.com'\n  GITHUB_REPOSITORY = 'gaetanlhf/EXPOSE'\n```\n\n3. Configure optional settings:\n   - Adjust `NAMED_TUNNELS_RANGE` and `RANDOM_TUNNELS_RANGE` for tunnel allocation\n   - Set `TIMEOUT` for session duration (in minutes)\n   - Modify `LOG_LEVEL` for debugging (`DEBUG`, `INFO`, `WARNING`, `ERROR`)\n\n### Deploy to Fly.io\n\n1. Launch the application:\n```bash\nfly launch\n```\n\n2. Add the SSH private key secret:\n```bash\nfly secrets set SSH_SERVER_KEY=\"$(cat ssh_key)\"\n```\n\n3. Configure DNS to point your domains to Fly.io's IPv4 and IPv6 addresses\n\n4. Add HTTPS certificates in the Fly.io dashboard for your domains\n\n## Configuration Variables\n\n### Required Variables\n| Variable | Description | Example |\n|----------|-------------|---------|\n| `app` | Fly.io application name | `my-expose-server` |\n| `primary_region` | Fly.io deployment region | `cdg`, `lax`, `fra` |\n| `FLYDOTIO_APP_NAME` | Must match the app name | `my-expose-server` |\n| `HTTP_URL` | Domain for tunnel URLs | `expos.es` |\n| `SSH_SERVER_URL` | SSH connection endpoint | `expose.sh` |\n| `GITHUB_REPOSITORY` | Repository to check for stargazers | `gaetanlhf/EXPOSE` |\n\n### Optional Variables\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `NAMED_TUNNELS_RANGE` | `1-3` | Slots for username-based naming |\n| `RANDOM_TUNNELS_RANGE` | `4-5` | Slots for random naming |\n| `TIMEOUT` | `120` | Session timeout in minutes |\n| `LOG_LEVEL` | `INFO` | Logging level (`DEBUG`, `INFO`, `WARNING`, `ERROR`) |\n| `SSH_SERVER_PORT` | `2222` | Internal SSH server port |\n| `NODEJS_TOOLS_PORT` | `3000` | Internal tools service port |\n\n## Usage Examples\n\nSingle tunnel:\n```bash\nssh -R 1:localhost:3000 expose.sh\n```\n\nMultiple tunnels:\n```bash\nssh -R 1:localhost:3000 -R 2:localhost:8080 expose.sh\n```\n\nAuto-reconnect:\n```bash\nuntil ssh -R 1:localhost:3000 expose.sh; do echo \"Reconnecting...\"; done\n```\n\n## FAQs\n\n\u003cdetails\u003e\n\u003csummary\u003eIs EXPOSE secure?\u003c/summary\u003e\nYes, SSH is an encrypted protocol, and access to your application is secure thanks to automatic HTTPS certificates.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWhat do you mean by no installation and no configuration?\u003c/summary\u003e\n\u003cstrong\u003eNo installation\u003c/strong\u003e because EXPOSE uses your existing SSH client. \u003cstrong\u003eNo configuration\u003c/strong\u003e because EXPOSE automatically retrieves data from your SSH client and GitHub account.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eHow many tunnels can I create simultaneously?\u003c/summary\u003e\nYou can create up to 10 simultaneous tunnels. Slots 1-3 use your username, slots 4-5 use your username + random chars.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWhat's the session time limit?\u003c/summary\u003e\nEach session lasts up to 2 hours, but you can reconnect unlimited times.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eI see \"Cannot connect to your local application\" in the browser\u003c/summary\u003e\nEnsure your local application is running and accessible at `http://localhost:port`.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eI see \"connect_to localhost port failed\" in terminal\u003c/summary\u003e\nVerify your local service is running on the specified port by testing `http://localhost:port` in your browser.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eDoes EXPOSE support other protocols?\u003c/summary\u003e\nEXPOSE supports HTTP, HTTPS, and WebSocket protocols.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWhere can I get help?\u003c/summary\u003e\nOpen an issue on this repository or send an email to \u003ca href=\"mailto:gaetan@expose.sh\"\u003egaetan@expose.sh\u003c/a\u003e.\n\u003c/details\u003e\n\n## License\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaetanlhf%2FEXPOSE","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgaetanlhf%2FEXPOSE","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaetanlhf%2FEXPOSE/lists"}