{"id":13492293,"url":"https://github.com/naggie/dsnet","last_synced_at":"2025-04-12T14:57:26.191Z","repository":{"id":37687763,"uuid":"239564831","full_name":"naggie/dsnet","owner":"naggie","description":"FAST command to manage a centralised wireguard VPN. Think wg-quick but quicker: key generation + address allocation.","archived":false,"fork":false,"pushed_at":"2024-08-13T19:33:07.000Z","size":5699,"stargazers_count":694,"open_issues_count":13,"forks_count":32,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-10T05:52:57.590Z","etag":null,"topics":["edgeos","edgerouter","ipv4","ipv6","linux","networking","ubuntu","vpn","vyatta","wireguard"],"latest_commit_sha":null,"homepage":"https://calbryant.uk/blog/how-to-set-up-a-wireguard-vpn-in-minutes-with-dsnet/","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/naggie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2020-02-10T16:58:57.000Z","updated_at":"2025-04-09T17:47:16.000Z","dependencies_parsed_at":"2024-06-02T01:41:05.675Z","dependency_job_id":"259040af-0f62-449a-83e9-7cdad9f2036f","html_url":"https://github.com/naggie/dsnet","commit_stats":{"total_commits":343,"total_committers":17,"mean_commits":"20.176470588235293","dds":0.2594752186588921,"last_synced_commit":"a24e64a2800f4a49f29cdac82f5799ae2262ea14"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/naggie%2Fdsnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/naggie%2Fdsnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/naggie%2Fdsnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/naggie%2Fdsnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/naggie","download_url":"https://codeload.github.com/naggie/dsnet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248287937,"owners_count":21078811,"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":["edgeos","edgerouter","ipv4","ipv6","linux","networking","ubuntu","vpn","vyatta","wireguard"],"created_at":"2024-07-31T19:01:04.753Z","updated_at":"2025-04-12T14:57:26.169Z","avatar_url":"https://github.com/naggie.png","language":"Go","funding_links":[],"categories":["Go","vpn"],"sub_categories":[],"readme":"\n\u003cimg src=\"/etc/logo/banner.svg\" alt=\"Dsnet banner\" width=\"100%\"\u003e\n\n\u003ca href=\"https://repology.org/project/dsnet/versions\"\u003e\n    \u003cbr /\u003e\n    \u003cimg src=\"https://repology.org/badge/vertical-allrepos/dsnet.svg\" alt=\"Packaging status\" align=\"right\"\u003e\n\u003c/a\u003e\n\n\u003cp\u003e\n\u003ca href=\"https://goreportcard.com/report/github.com/naggie/dsnet\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/naggie/dsnet\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" /\u003e\u003c/a\u003e\n\u003ca href=\"http://godoc.org/github.com/naggie/dsnet\"\u003e\u003cimg src=\"https://img.shields.io/badge/godoc-reference-blue.svg\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c!-- fine line --\u003e\u003ch1 align=\"center\"\u003e\u003c/h1\u003e\n\n\u003cbr\u003e\n\u003cbr\u003e\n\u003cbr\u003e\n\nSet up a VPN in one minute:\n\n\n![dsnet add](https://raw.githubusercontent.com/naggie/dsnet/master/etc/init+add.png)\n\nThe server peer is listening, and a client peer config has been generated and\nadded to the server peer:\n\n![wg](https://raw.githubusercontent.com/naggie/dsnet/master/etc/wg2.png)\n\nMore client peers can be added with `dsnet add`. They can connect immediately\nafter! Don't forget to [enable IP forwarding](https://askubuntu.com/questions/311053/how-to-make-ip-forwarding-permanent)\nto allow peers to talk to one another.\n\nIt works on AMD64 based linux and also ARMv5.\n\n    Usage:\n        dsnet [command]\n\n    Available Commands:\n      add         Add a new peer + sync\n      down        Destroy the interface, run pre/post down\n      help        Help about any command\n      init        Create /etc/dsnetconfig.json containing default configuration + new keys without loading. Edit to taste.\n      regenerate  Regenerate keys and config for peer\n      remove      Remove a peer by hostname provided as argument + sync\n      report      Generate a JSON status report to stdout\n      sync        Update wireguard configuration from /etc/dsnetconfig.json after validating\n      up          Create the interface, run pre/post up, sync\n      version     Print version\n\n    Flags:\n      -h, --help            help for this command\n          --output string   config file format: vyatta/wg-quick/nixos (default \"wg-quick\")\n\n    Use \"dsnet [command] --help\" for more information about a command.\n\n\nQuick start (AMD64 linux) -- install wireguard, then, after making sure `/usr/local/bin` is in your path:\n\n    sudo wget https://github.com/naggie/dsnet/releases/latest/download/dsnet-linux-amd64 -O /usr/local/bin/dsnet\n    sudo chmod +x /usr/local/bin/dsnet\n    sudo dsnet init\n    # edit /etc/dsnetconfig.json to taste\n    sudo dsnet up\n\tsudo dsnet add banana \u003e dsnet-banana.conf\n\tsudo dsnet add apple \u003e dsnet-apple.conf\n    # enable IP forwarding to allow peers to talk to one another\n    sudo sysctl -w net.ipv4.ip_forward=1   # edit /etc/sysctl.conf to make this persistent across reboots\n\nCopy the generated configuration file to your device and connect!\n\nTo send configurations, here are a few suggestions.\n- [ffsend](https://github.com/timvisee/ffsend), the most straightforward option;\n- [magic wormhole](https://magic-wormhole.readthedocs.io/), a more advanced\n  option, where the file never passes through another server;\n- [wormhole-william](https://github.com/psanford/wormhole-william), a Go\n  implementation of the above.\n\nFor the above options, one should transfer the password separately.\n\nA local QR code generator, such as the popular\n[qrencode](https://fukuchi.org/works/qrencode/) may also be used to generate a\nQR code of the configuration. For instance: `dsnet add | qrencode -t ansiutf8`.\nThis works because the dsnet prompts are on STDERR and not passed to qrencode.\n\nThe peer private key is generated on the server, which is technically not as\nsecure as generating it on the client peer and then providing the server the\npublic key; there is provision to specify a public key in the code when adding\na peer to avoid the server generating the private key. The feature will be\nadded when requested.\n\nNote that named arguments can be specified on the command line as well as\nentered by prompt; this allows for unattended usage.\n\n# GUI\n\nDsnet does not include or require a GUI, however there is now a separate\nofficial monitoring GUI: \u003chttps://github.com/botto/dsnet-gui\u003e.\n\n# Configuration overview\n\nThe configuration is a single JSON file. Beyond possible initial\ncustomisations, the file is managed entirely by dsnet.\n\ndsnetconfig.json is the only file the server needs to run the VPN. It contains\nthe server keys, peer public/shared keys and IP settings. **A working version is\nautomatically generated by `dsnet init` which can be modified as required.**\n\nCurrently its location is fixed as all my deployments are for a single network.\nI may add a feature to allow setting of the location via environment variable\nin the future to support multiple networks on a single host.\n\nMain (automatically generated) configuration example:\n\n\n    {\n        \"ExternalHostname\": \"\",\n        \"ExternalIP\": \"198.51.100.2\",\n        \"ExternalIP6\": \"2001:0db8:85a3:0000:0000:8a2e:0370:7334\",\n        \"ListenPort\": 51820,\n        \"Domain\": \"dsnet\",\n        \"InterfaceName\": \"dsnet\",\n        \"Network\": \"10.164.236.0/22\",\n        \"Network6\": \"fd00:7b31:106a:ae00::/64\",\n        \"IP\": \"10.164.236.1\",\n        \"IP6\": \"fd00:d631:74ca:7b00:a28:11a1:b821:f013\",\n        \"DNS\": \"\",\n        \"Networks\": [],\n        \"PrivateKey\": \"uC+xz3v1mfjWBHepwiCgAmPebZcY+EdhaHAvqX2r7U8=\",\n        \"PostUp\": \"\",\n        \"PostDown\" \"\",\n        \"Peers\": [\n            {\n                \"Hostname\": \"test\",\n                \"Owner\": \"naggie\",\n                \"Description\": \"Home server\",\n                \"IP\": \"10.164.236.2\",\n                \"IP6\": \"fd00:7b31:106a:ae00:44c3:29c3:53b1:a6f9\",\n                \"Added\": \"2020-05-07T10:04:46.336286992+01:00\",\n                \"Networks\": [],\n                \"PublicKey\": \"altJeQ/V52JZQrGcA9RiKcpZusYU6zMUJhl7Wbd9rX0=\",\n                \"PresharedKey\": \"GcUtlze0BMuxo3iVEjpOahKdTf8xVfF8hDW3Ylw5az0=\"\n            }\n        ]\n    }\n\n\nSee [CONFIG.md](CONFIG.md) for an explanation of each field.\n\n\n# Report file overview\n\nAn example report file, generated by `dsnet report`. Suggested location:\n`/var/lib/dsnetreport.json`:\n\n    {\n        \"ExternalIP\": \"198.51.100.2\",\n        \"InterfaceName\": \"dsnet\",\n        \"ListenPort\": 51820,\n        \"Domain\": \"dsnet\",\n        \"IP\": \"10.164.236.1\",\n        \"Network\": \"10.164.236.0/22\",\n        \"DNS\": \"\",\n        \"PeersOnline\": 4,\n        \"PeersTotal\": 13,\n        \"ReceiveBytes\": 32517164,\n        \"TransmitBytes\": 85384984,\n        \"ReceiveBytesSI\": \"32.5 MB\",\n        \"TransmitBytesSI\": \"85.4 MB\",\n        \"Peers\": [\n            {\n                \"Hostname\": \"test\",\n                \"Owner\": \"naggie\",\n                \"Description\": \"Home server\",\n                \"Online\": false,\n                \"Dormant\": true,\n                \"Added\": \"2020-03-12T20:15:42.798800741Z\",\n                \"IP\": \"10.164.236.2\",\n                \"ExternalIP\": \"198.51.100.223\",\n                \"Networks\": [],\n                \"Added\": \"2020-05-07T10:04:46.336286992+01:00\",\n                \"ReceiveBytes\": 32517164,\n                \"TransmitBytes\": 85384984,\n                \"ReceiveBytesSI\": \"32.5 MB\",\n                \"TransmitBytesSI\": \"85.4 MB\"\n            }\n\n            \u003c...\u003e\n        ]\n    }\n\nFields mean the same as they do above, or are self explanatory. Note that some\ndata is converted into human readable formats in addition to machine formats --\nthis is technically redundant but useful with Hugo shortcodes and other site generators.\n\nThe report can be converted, for instance, into a HTML table as below:\n\n![dsnet report table](https://raw.githubusercontent.com/naggie/dsnet/master/etc/report.png)\n\nSee\n[etc/README.md](https://github.com/naggie/dsnet/blob/master/contrib/report_rendering/README.md)\nfor hugo and PHP code for rendering a similar table.\n\n# Generating other config files\n\ndsnet currently supports the generation of a `wg-quick` configuration by\ndefault. It can also generate VyOS/Vyatta configuration for EdgeOS/Unifi devices\nsuch as the Edgerouter 4 using the\n[wireguard-vyatta](https://github.com/WireGuard/wireguard-vyatta-ubnt) package,\nas well as configuration for [NixOS](https://nixos.org), ready to be added to\n`configuration.nix` environment definition. [MikroTik RouterOS](https://mikrotik.com/software)\nsupport is also available.\n\nTo change the config file format, set the following environment variables:\n\n* `DSNET_OUTPUT=vyatta`\n* `DSNET_OUTPUT=wg-quick`\n* `DSNET_OUTPUT=nixos`\n* `DSNET_OUTPUT=routeros`\n\nExample vyatta output:\n\n    configure\n    set interfaces wireguard wg23 address 10.165.52.3/22\n    set interfaces wireguard wg23 address fd00:7b31:106a:ae00:f7bb:bf31:201f:60ab/64\n    set interfaces wireguard wg23 route-allowed-ips true\n    set interfaces wireguard wg23 private-key cAtj1tbjGGmVoxdY78q9Sv0EgNlawbzffGWjajQkLFw=\n    set interfaces wireguard wg23 description dsnet\n\n    set interfaces wireguard wg23 peer PjxQM7OwVYvOJfORA1EluLw8CchSu7jLq92YYJi5ohY= endpoint 123.123.123.123:51820\n    set interfaces wireguard wg23 peer PjxQM7OwVYvOJfORA1EluLw8CchSu7jLq92YYJi5ohY= persistent-keepalive 25\n    set interfaces wireguard wg23 peer PjxQM7OwVYvOJfORA1EluLw8CchSu7jLq92YYJi5ohY= preshared-key w1FtOKoMEdnhsjREtSvpg1CHEKFzFzJWaQYZwaUCV38=\n    set interfaces wireguard wg23 peer PjxQM7OwVYvOJfORA1EluLw8CchSu7jLq92YYJi5ohY= allowed-ips 10.165.52.0/22\n    set interfaces wireguard wg23 peer PjxQM7OwVYvOJfORA1EluLw8CchSu7jLq92YYJi5ohY= allowed-ips fd00:7b31:106a:ae00::/64\n    commit; save\n\nThe interface (in this case `wg23`) is deterministically chosen in the range\n`wg0-wg999`. This is such that you can use multiple dsnet configurations and\nthe interface numbers will (probably) be different. The interface number is\narbitrary, so if it is already assigned replace it with a number of your\nchoice.\n\nExample NixOS output:\n\n    networking.wireguard.interfaces = {\n      dsnet = {\n        ips = [\n          \"10.9.8.2/22\"\n          \"fd00:80f8:af4a:4700:aaaa:bbbb:cccc:88ad/64\"\n          ];\n        privateKey = \"2PvML6bsmTCK+cBxpV9SfF261fsH6gICixtppfG6KFc=\";\n        peers = [\n          {\n            publicKey = \"zCDo5yn7Muy3mPBXtarwm5S7JjNKM0IdIdGqoreWmSA=\";\n            presharedKey = \"5Fa8Zc8gIkpfBPJUJn5OEVuE00iqmXnS34v4evv1MUM=\";\n            allowedIPs = [\n              \"10.56.72.0/22\"\n              \"fd00:80f8:af4a:4700::/64\"\n              ];\n            endpoint = \"123.123.123.123:51820\";\n            persistentKeepalive = 25;\n          }\n        ];\n      };\n    };\n\nExample MikroTik RouterOS output:\n\n    /interface wireguard\n    add name=wg0 private-key=\"CDWdi0IcMZgla1hCYI41JejjuFaPCle+vPBxvX5OvVE=\";\n    /interface list member\n    add interface=wg0 list=LAN\n    /ip address\n    add address=10.55.148.2/22 interface=wg0\n    /ipv6 address\n    add address=fd00:1965:946d:5000:5a88:878d:dc0:c777/64 advertise=no eui-64=no no-dad=no interface=wg0\n    /interface wireguard peers\n    add interface=wg0 \\\n        public-key=\"iE7dleTu34JOCC4A8xdIZcnbNE+aoji8i1JpP+gdt0M=\" \\\n        preshared-key=\"Ch0BdZ6Um29D34awlWBSNa+cz1wGOUuHshjYIyqKxGU=\" \\\n        endpoint-address=198.51.100.73 \\\n        endpoint-port=51820 \\\n        persistent-keepalive=25s \\\n        allowed-address=10.55.148.0/22,fd00:1965:946d:5000::/64,192.168.10.0/24,fe80::1/64\n\n# FAQ\n\n\u003e Does dsnet support IPv6?\n\nYes! By default since version 0.2, a random ULA subnet is generated with a 0\nsubnet ID. Peers are allocated random addresses when added. Existing IPv4\nconfigs will not be updated -- add a `Network6` subnet to the existing config\nto allocate addresses to new peers.\n\nLike IPv4, it's up to you if you want to provide NAT IPv6 access to the\ninternet; alternatively (and preferably) you can allocate a a real IPv6 subnet\nsuch that all peers have a real globally routeable IPv6 address.\n\nUpon initialisation, the server IPv4 and IPv6 external IP addresses are\ndiscovered on a best-effort basis. Clients will have configuration configured\nfor the server IPv4 preferentially. If not IPv4 is configured, IPv6 is used;\nthis is to give the best chance of the VPN working regardless of the dodgy\nnetwork you're on.\n\n\u003e Is dsnet production ready?\n\nAbsolutely, it's just a configuration generator so your VPN does not depend on\ndsnet after adding peers. I use it in production at 2 companies so far.\n\nNote that before version 1.0, the config file schema may change. Changes will\nbe made clear in release notes.\n\n\u003e Client private keys are generated on the server. Can I avoid this?\n\nAllowing generation of the pub/priv keypair on the client is not yet supported,\nbut will be soon as provision exists within the code base. Note that whilst\nclient peer private keys are generated on the server, they are never stored.\n\n\n\u003e How do I get dsnet to bring the (server) interface up on startup?\n\nAssuming you're running a systemd powered linux distribution (most of them are):\n\n1. Copy\n   [etc/dsnet.service](https://github.com/naggie/dsnet/blob/master/etc/dsnet.service)\n   to `/etc/systemd/system/`\n2. Run `sudo systemctl daemon-reload` to get systemd to see it\n3. Then run `sudo systemctl enable dsnet` to enable it at boot\n\n\u003e How can I generate the report periodically?\n\nEither with cron or a systemd timer. Cron is easiest:\n\n    echo '* * * * * root /usr/local/bin/dsnet report | sudo tee /etc/cron.d/dsnetreport'\n\nNote that whilst report generation requires root, consuming the report does not\nas it's just a world-readable file. This is important for web interfaces that\nneed to be secure.\n\nThis is also why dsnet loads its configuration from a file -- it's possible to\nset permissions such that dsnet synchronises the config generated by a non-root\nuser. Combined with a periodic `dsnet sync` like above, it's possible to build\na secure web interface that does not require root. A web interface is currently\nbeing created by a friend; it will not be part of dstask, rather a separate\nproject.\n\n----\n\nThe dsnet logo was kindly designed by [@mirorauhala](https://github.com/mirorauhala).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnaggie%2Fdsnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnaggie%2Fdsnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnaggie%2Fdsnet/lists"}