{"id":50103553,"url":"https://github.com/venkatkrishna07/mkdev","last_synced_at":"2026-05-23T09:01:35.045Z","repository":{"id":359344586,"uuid":"1236319803","full_name":"venkatkrishna07/mkdev","owner":"venkatkrishna07","description":"Trusted localhost HTTPS — local CA, /etc/hosts, mDNS LAN sharing, reverse proxy. Maps https://name.local →    localhost:port","archived":false,"fork":false,"pushed_at":"2026-05-21T12:30:35.000Z","size":1841,"stargazers_count":3,"open_issues_count":5,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T20:56:05.636Z","etag":null,"topics":["cli","developer-tools","golang","homebrew","local-development","localhost","mdns","mkcert","tui"],"latest_commit_sha":null,"homepage":"","language":"Go","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/venkatkrishna07.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","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":"2026-05-12T06:28:18.000Z","updated_at":"2026-05-21T20:24:03.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/venkatkrishna07/mkdev","commit_stats":null,"previous_names":["venkatkrishna07/mkdev"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/venkatkrishna07/mkdev","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venkatkrishna07%2Fmkdev","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venkatkrishna07%2Fmkdev/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venkatkrishna07%2Fmkdev/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venkatkrishna07%2Fmkdev/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/venkatkrishna07","download_url":"https://codeload.github.com/venkatkrishna07/mkdev/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venkatkrishna07%2Fmkdev/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33389229,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["cli","developer-tools","golang","homebrew","local-development","localhost","mdns","mkcert","tui"],"created_at":"2026-05-23T09:01:33.730Z","updated_at":"2026-05-23T09:01:35.032Z","avatar_url":"https://github.com/venkatkrishna07.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mkdev\n\n**Real HTTPS for local dev — with a TUI and LAN sharing.**\n\n[![ci](https://github.com/venkatkrishna07/mkdev/actions/workflows/ci.yml/badge.svg)](https://github.com/venkatkrishna07/mkdev/actions/workflows/ci.yml) [![release](https://github.com/venkatkrishna07/mkdev/actions/workflows/release.yml/badge.svg)](https://github.com/venkatkrishna07/mkdev/actions/workflows/release.yml) [![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)\n\n---\n\nmkdev runs trusted HTTPS on `*.local`.  A single Go binary: cert authority + reverse proxy + `/etc/hosts` + mDNS broadcast + a full TUI.\n\nWhat makes it different:\n\n- **LAN sharing** Mark a route shared, hit `https://app.local` from your phone or any device on the same Wi-Fi.\n- **TUI, not just a CLI.** Live route table, request logs, cert inspection, health doctor. `mkdev` with no args drops you in.\n- **Hardened privilege boundary.** Owner, writability, and symlink checks on the sudo helper binary before any elevated call ([`internal/safeexec`](./internal/safeexec/safeexec.go)). No PATH-based shadowing, no group-writable shortcuts.\n- **Per-SNI cert minting.** Leaves are issued on demand and gated by an explicit `knownHost` allow-list. Not wildcard, not pre-baked.\n\n## What it does\n\n```\nmkdev install                    # generates CA, trusts in system store\nmkdev add myapp localhost:3000   # routes https://myapp.local → localhost:3000\nmkdev serve                      # foreground TLS proxy\ncurl https://myapp.local         # 200 from your local app\n```\n\n![mkdev demo](assets/demo-add.gif)\n\n## LAN sharing\n\nmkdev's headline feature. Share a route to any device on the same Wi-Fi with real TLS — no warnings, no tunnel service.\n\n1. In the TUI Domains tab, select a route and press `s` to flip the **SHARE** column to `LAN`.\n2. The route is advertised via mDNS as `\u003cname\u003e.local` → this machine's LAN IP.\n3. On the phone / second laptop, browse to `https://\u003cname\u003e.local`. Once the device trusts the mkdev CA (one-time), no warnings.\n\n### Caveats\n\n- Only `.local` routes broadcast over mDNS. Other TLDs still proxy but aren't LAN-reachable by name.\n- Corporate / cloud Wi-Fi often blocks multicast. Home and office Wi-Fi work.\n- Toggling `s` is live — mDNS advertising and the LAN-side ACL update on the next request. No restart.\n- Non-shared routes 403 non-loopback requests as defense-in-depth.\n- Anyone on the LAN can hit your shared routes. Don't enable on untrusted Wi-Fi.\n\n## Install\n\n### Homebrew (macOS, Linux)\n\n```sh\nbrew install venkatkrishna07/tap/mkdev\n```\n\nUpgrade later:\n\n```sh\nbrew update\nbrew upgrade mkdev\n```\n\n### Go\n\n```sh\ngo install github.com/venkatkrishna07/mkdev/cmd/mkdev@latest\n```\n\nUpgrade to a specific version:\n\n```sh\ngo install github.com/venkatkrishna07/mkdev/cmd/mkdev@v0.2.0\n```\n\n### Direct download\n\nPre-built binaries for macOS (Intel + Apple Silicon), Linux (amd64 + arm64), and Windows (amd64) are published on the [Releases page](https://github.com/venkatkrishna07/mkdev/releases). Each release includes `checksums.txt` plus a cosign keyless signature (`checksums.txt.sig` + `.pem`) — see [SECURITY.md#verifying-releases](./SECURITY.md) for the verify command.\n\nOn macOS, if Gatekeeper blocks a direct-download binary:\n\n```sh\nxattr -d com.apple.quarantine ./mkdev\n```\n\n### From source\n\n```sh\ngit clone https://github.com/venkatkrishna07/mkdev.git\ncd mkdev\ntask build\ncp bin/mkdev ~/bin/        # or /usr/local/bin\n```\n\nRequires **Go 1.25+**.\n\n## First run\n\n```sh\nmkdev install   # one-time root CA trust\nmkdev           # launch TUI\n```\n\n## Platform support\n\n| Platform | Trust store                                                       | Elevation       |\n|----------|-------------------------------------------------------------------|-----------------|\n| macOS    | System Keychain (`security add-trusted-cert`)                     | `sudo` / `osascript` |\n| Linux    | `update-ca-trust` / `update-ca-certificates` / `trust extract-compat` | `sudo` / `pkexec` |\n| Windows  | `ROOT` system store via `crypt32.dll`                             | UAC (PowerShell `RunAs`) |\n\nLinux distros detected: Debian/Ubuntu (`/usr/local/share/ca-certificates`), RHEL/Fedora (`/etc/pki/ca-trust/source/anchors`), Arch (`/etc/ca-certificates/trust-source/anchors`), openSUSE (`/usr/share/pki/trust/anchors`).\n\nFirefox uses its own NSS store and is **not yet covered** — system Chrome/Safari/Edge/curl/wget all work.\n\n## Commands\n\n| Command                              | Purpose                                                       |\n|--------------------------------------|---------------------------------------------------------------|\n| `install`                            | Generate the root CA, write defaults, trust in system store.  |\n| `add \u003cname\u003e \u003ctarget\u003e`                | Add route. Appends a `127.0.0.1` entry to `/etc/hosts`.       |\n| `remove \u003cname\u003e`                      | Remove route and its `/etc/hosts` entry.                      |\n| `list`                               | List routes in the store.                                     |\n| `serve`                              | Run the TLS reverse proxy in the foreground.                  |\n| `tui`                                | Launch the TUI (also the default when run with no args).      |\n| `uninstall`                          | Untrust the CA. `--purge` also wipes `~/.mkdev/`.             |\n| `version`                            | Print version, commit, build date.                            |\n| `completion \u003cbash\\|zsh\\|fish\\|powershell\u003e` | Emit shell completion script.                                 |\n| `hosts-helper`                       | Hidden. Invoked via `sudo` to mutate `/etc/hosts` atomically. |\n\n### Flags and environment\n\n| Flag / env                    | Effect                                                       |\n|-------------------------------|--------------------------------------------------------------|\n| `--home \u003cpath\u003e`               | Override `~/.mkdev` state directory.                         |\n| `--verbose`, `-v`             | Debug-level logging to stderr.                               |\n| `--version`                   | Print version and exit.                                      |\n| `MKDEV_HOME=\u003cpath\u003e`           | Equivalent to `--home`.                                      |\n\n### Target formats\n\n`\u003ctarget\u003e` accepts any of:\n\n```\nhost:port                  e.g. localhost:3000\nhttp://host[:port]/path    e.g. http://localhost:3000/api\nhttps://host[:port]/path   e.g. https://gitlab.example.com\n```\n\nFor HTTPS upstreams (e.g., a private GitLab on a corporate VPN) the upstream's TLS cert must verify against the system trust store. Private CAs need their root added to the OS keychain.\n\n`hosts-helper` is not meant to be called directly. `add` / `remove` re-invoke the same binary under `sudo` to perform the privileged `/etc/hosts` write.\n\n## Configuration\n\n\u003e **TLD note.** `.local` routes need an mDNS responder (always-on on macOS, available on Linux when `nss-mdns` is installed). `.test` / `.dev` / `.localhost` work everywhere via `/etc/hosts` alone. Set `tld` in config to match.\n\nConfig lives at `~/.mkdev/config.toml`. Defaults:\n\n```toml\ntld           = \".local\"   # appended to bare names in `add`\nproxy_port    = 443        # binding :443 requires sudo on serve\ntheme         = \"auto\"     # reserved for future TUI\nlog_retention = \"7d\"       # reserved\nlog_max_size  = \"100MB\"    # reserved\n```\n\n| Field           | Default     | Notes                                                       |\n|-----------------|-------------|-------------------------------------------------------------|\n| `tld`           | `.local`    | Auto-appended when `add \u003cname\u003e` has no dot.                 |\n| `proxy_port`    | `443`       | Set to `8443` to run `serve` without sudo for dev testing.  |\n| `theme`         | `auto`      | Reserved for the upcoming TUI.                              |\n| `log_retention` | `7d`        | Reserved.                                                   |\n| `log_max_size`  | `100MB`     | Reserved.                                                   |\n\nOverride the config directory with `--home \u003cpath\u003e` or `MKDEV_HOME=...`.\n\n## How it works\n\n- Generates an **ECDSA P-256** root CA at `~/.mkdev/ca/`. The private key is mode `0o400`.\n- Installs the CA in the OS-native trust store: macOS Keychain (`security`), Linux CA-bundle directory + `update-ca-*`, Windows `ROOT` store via `crypt32.dll`. Trust-store integration is adapted from [mkcert](https://github.com/FiloSottile/mkcert) (BSD-3) — see [`LICENSE-MKCERT`](./LICENSE-MKCERT).\n- On `add`, writes a route to a **bbolt** KV at `~/.mkdev/state.db` and appends a `127.0.0.1 \u003cname\u003e.\u003ctld\u003e` line to `/etc/hosts` via a `sudo`-invoked helper subcommand.\n- `serve` listens TLS on `0.0.0.0:\u003cproxy_port\u003e`, **mints leaf certs per SNI** on demand using the root CA, and reverse-proxies to the configured upstream.\n- The route table is re-read every 2 seconds, so `add` / `remove` take effect without restarting `serve`.\n- The proxy binds `0.0.0.0`, but non-loopback requests are 403'd unless the matching route is marked **shared** — see [LAN sharing](#lan-sharing--your-dev-server-on-your-phone).\n\n## Security\n\nThis tool installs a **private CA into your system trust store**. Anyone with read access to `~/.mkdev/ca/rootCA-key.pem` can mint TLS certs that your machine will trust. The key is created `0o400` (owner read only).\n\n- The proxy binds `0.0.0.0`, but a connection-source ACL 403s LAN requests to any route not explicitly marked **shared**. Loopback always passes.\n- No telemetry. No remote calls. No update checks.\n- `add` / `remove` invoke `sudo` to mutate `/etc/hosts`. See [SECURITY.md](./SECURITY.md) for the threat model and a known limit around `os.Executable()`-resolved helper paths.\n\n## Uninstall\n\n```sh\nmkdev uninstall           # untrust CA, remove /etc/hosts entries\nmkdev uninstall --purge   # also delete ~/.mkdev/\n```\n\nIf something gets stuck, open **Keychain Access.app**, search for `mkdev`, and delete by hand. Then `grep mkdev /etc/hosts` and clean any leftovers.\n\n\n## Roadmap\n\nNext:\n\n- Background daemon (`mkdev up` / `mkdev down`); UDS IPC; launchd / systemd / Task Scheduler.\n- Project config file (`.mkdev.yaml` checked into the repo).\n- Firefox / NSS trust store integration.\n- Per-path routing (`/api` → 8080, `/ws` → 9000 on a single domain).\n\n## Troubleshooting\n\n- **Firefox shows a red bar.** Firefox uses its own NSS store; system trust doesn't reach it. NSS integration is on the roadmap. For now, import `~/.mkdev/ca/rootCA.pem` manually under Settings → Privacy \u0026 Security → Certificates → View Certificates → Authorities → Import.\n- **`serve` fails with \"permission denied\" on :443.** Either run as root, or set `proxy_port = 8443` in `~/.mkdev/config.toml` and use `https://name.local:8443`.\n- **`mkdev add` keeps asking for sudo.** Sudo's per-session cache expires (default 5 min). Use the TUI Domains tab instead — it elevates via `osascript` (macOS GUI prompt) or `pkexec` (Linux Polkit).\n- **`/etc/hosts` already has an entry for that name.** `mkdev add` is idempotent and only appends when no `mkdev`-managed entry exists. Remove the prior entry by hand or pick a different name.\n\n## Contributing\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## Acknowledgements\n\nmkdev's trust-store integration — Keychain/`security` on macOS, CA-bundle + `update-ca-*` on Linux, `crypt32.dll` `ROOT` store on Windows, and the NSS adjacent paths — is adapted from [**mkcert**](https://github.com/FiloSottile/mkcert) by Filippo Valsorda, BSD-3. Without that prior art, this project would be substantially harder. See [`LICENSE-MKCERT`](./LICENSE-MKCERT) for the upstream license.\n\nThe TUI is built with [Charmbracelet's](https://charm.sh) Bubble Tea / Bubbles / Lipgloss. mDNS via [`hashicorp/mdns`](https://github.com/hashicorp/mdns). Local KV via [`bbolt`](https://github.com/etcd-io/bbolt).\n\n## License\n\nMIT   [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvenkatkrishna07%2Fmkdev","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvenkatkrishna07%2Fmkdev","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvenkatkrishna07%2Fmkdev/lists"}