Browse Source

Merge branch 'develop' into feature-messageQueue

Matthew R Kasun 3 years ago
parent
commit
c239ee3787
42 changed files with 948 additions and 184 deletions
  1. 0 0
      compose/docker-compose.hostnetwork.yml
  2. 64 0
      compose/docker-compose.nocaddy.yml
  3. 2 0
      compose/docker-compose.reference.yml
  4. 19 8
      compose/docker-compose.yml
  5. 1 0
      config/config.go
  6. 31 18
      controllers/server_util.go
  7. 31 1
      database/database.go
  8. BIN
      docs/_build/doctrees/api.doctree
  9. BIN
      docs/_build/doctrees/architecture.doctree
  10. BIN
      docs/_build/doctrees/client-installation.doctree
  11. BIN
      docs/_build/doctrees/environment.pickle
  12. BIN
      docs/_build/doctrees/server-installation.doctree
  13. BIN
      docs/_build/doctrees/support.doctree
  14. BIN
      docs/_build/doctrees/troubleshoot.doctree
  15. 59 47
      docs/_build/html/_sources/api.rst.txt
  16. 14 4
      docs/_build/html/_sources/architecture.rst.txt
  17. 23 0
      docs/_build/html/_sources/client-installation.rst.txt
  18. 52 8
      docs/_build/html/_sources/server-installation.rst.txt
  19. 27 0
      docs/_build/html/_sources/support.rst.txt
  20. 7 0
      docs/_build/html/_sources/troubleshoot.rst.txt
  21. 60 27
      docs/_build/html/api.html
  22. 12 1
      docs/_build/html/architecture.html
  23. 39 2
      docs/_build/html/client-installation.html
  24. 1 0
      docs/_build/html/index.html
  25. 0 0
      docs/_build/html/searchindex.js
  26. 53 11
      docs/_build/html/server-installation.html
  27. 34 0
      docs/_build/html/support.html
  28. 5 1
      docs/_build/html/troubleshoot.html
  29. 59 47
      docs/api.rst
  30. 11 1
      docs/architecture.rst
  31. 23 0
      docs/client-installation.rst
  32. 52 8
      docs/server-installation.rst
  33. 27 0
      docs/support.rst
  34. 7 0
      docs/troubleshoot.rst
  35. 2 0
      go.mod
  36. 5 0
      go.sum
  37. 2 0
      logic/nodes.go
  38. 4 0
      main.go
  39. 22 0
      models/node.go
  40. 6 0
      models/structs.go
  41. 13 0
      servercfg/serverconf.go
  42. 181 0
      serverctl/telemetry.go

+ 0 - 0
compose/docker-compose.caddy.yml → compose/docker-compose.hostnetwork.yml


+ 64 - 0
compose/docker-compose.nocaddy.yml

@@ -0,0 +1,64 @@
+version: "3.4"
+
+services:
+  netmaker:
+    container_name: netmaker
+    image: gravitl/netmaker:v0.9.4
+    volumes:
+      - dnsconfig:/root/config/dnsconfig
+      - /usr/bin/wg:/usr/bin/wg
+      - sqldata:/root/data
+    cap_add: 
+      - NET_ADMIN
+    restart: always
+    privileged: true
+    environment:
+      SERVER_HOST: "SERVER_PUBLIC_IP"
+      SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
+      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443"
+      COREDNS_ADDR: "SERVER_PUBLIC_IP"
+      GRPC_SSL: "on"
+      DNS_MODE: "on"
+      SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
+      SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN"
+      API_PORT: "8081"
+      GRPC_PORT: "50051"
+      CLIENT_MODE: "on"
+      MASTER_KEY: "REPLACE_MASTER_KEY"
+      SERVER_GRPC_WIREGUARD: "off"
+      CORS_ALLOWED_ORIGIN: "*"
+      DISPLAY_KEYS: "on"
+      DATABASE: "sqlite"
+      NODE_ID: "netmaker-server-1"
+    ports:
+      - "51821-51830:51821-51830/udp"
+      - "8081:8081"
+      - "50051:50051"
+  netmaker-ui:
+    container_name: netmaker-ui
+    depends_on:
+      - netmaker
+    image: gravitl/netmaker-ui:v0.9.3
+    links:
+      - "netmaker:api"
+    ports:
+      - "8082:80"
+    environment:
+      BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN"
+    restart: always
+  coredns:
+    depends_on:
+      - netmaker 
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile
+    container_name: coredns
+    restart: always
+    ports:
+      - "COREDNS_IP:53:53/udp"
+      - "COREDNS_IP:53:53/tcp"
+    volumes:
+      - dnsconfig:/root/dnsconfig
+volumes:
+  sqldata: {}
+  dnsconfig: {}
+

+ 2 - 0
compose/docker-compose.reference.yml

@@ -38,6 +38,8 @@ services:
       SERVER_API_CONN_STRING: "" # Changes the api connection string. IP:PORT format. By default is empty and uses SERVER_HOST:API_PORT
       SERVER_API_CONN_STRING: "" # Changes the api connection string. IP:PORT format. By default is empty and uses SERVER_HOST:API_PORT
       SERVER_GRPC_CONN_STRING: "" # Changes the grpc connection string. IP:PORT format. By default is empty and uses SERVER_HOST:GRPC_PORT
       SERVER_GRPC_CONN_STRING: "" # Changes the grpc connection string. IP:PORT format. By default is empty and uses SERVER_HOST:GRPC_PORT
       RCE: "off" # Enables setting PostUp and PostDown (arbitrary commands) on nodes from the server. Off by default.
       RCE: "off" # Enables setting PostUp and PostDown (arbitrary commands) on nodes from the server. Off by default.
+      NODE_ID: "" # Sets the name/id of the nodes that the server creates. Necessary for HA configurations to identify between servers (for instance, netmaker-1, netmaker-2, etc). For non-HA deployments, is not necessary.
+      TELEMETRY: "on" # Whether or not to send telemetry data to help improve Netmaker. Switch to "off" to opt out of sending telemetry.
   netmaker-ui: # The Netmaker UI Component
   netmaker-ui: # The Netmaker UI Component
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:

+ 19 - 8
compose/docker-compose.yml

@@ -5,18 +5,12 @@ services:
     container_name: netmaker
     container_name: netmaker
     image: gravitl/netmaker:v0.9.4
     image: gravitl/netmaker:v0.9.4
     volumes:
     volumes:
-      - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket
-      - /run/systemd/system:/run/systemd/system
-      - /etc/systemd/system:/etc/systemd/system
-      - /sys/fs/cgroup:/sys/fs/cgroup
-      - /usr/bin/wg:/usr/bin/wg
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
+      - /usr/bin/wg:/usr/bin/wg
       - sqldata:/root/data
       - sqldata:/root/data
     cap_add: 
     cap_add: 
       - NET_ADMIN
       - NET_ADMIN
-      - SYS_ADMIN
     restart: always
     restart: always
-    network_mode: host
     privileged: true
     privileged: true
     environment:
     environment:
       SERVER_HOST: "SERVER_PUBLIC_IP"
       SERVER_HOST: "SERVER_PUBLIC_IP"
@@ -33,9 +27,13 @@ services:
       MASTER_KEY: "REPLACE_MASTER_KEY"
       MASTER_KEY: "REPLACE_MASTER_KEY"
       SERVER_GRPC_WIREGUARD: "off"
       SERVER_GRPC_WIREGUARD: "off"
       CORS_ALLOWED_ORIGIN: "*"
       CORS_ALLOWED_ORIGIN: "*"
-      DATABASE: "sqlite"
       DISPLAY_KEYS: "on"
       DISPLAY_KEYS: "on"
+      DATABASE: "sqlite"
       NODE_ID: "netmaker-server-1"
       NODE_ID: "netmaker-server-1"
+    ports:
+      - "51821-51830:51821-51830/udp"
+      - "8081:8081"
+      - "50051:50051"
   netmaker-ui:
   netmaker-ui:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
@@ -60,6 +58,19 @@ services:
       - "COREDNS_IP:53:53/tcp"
       - "COREDNS_IP:53:53/tcp"
     volumes:
     volumes:
       - dnsconfig:/root/dnsconfig
       - dnsconfig:/root/dnsconfig
+  caddy:
+    image: caddy:latest
+    container_name: caddy
+    restart: unless-stopped
+    network_mode: host # Wants ports 80 and 443!
+    volumes:
+      - /root/Caddyfile:/etc/caddy/Caddyfile
+      # - $PWD/site:/srv # you could also serve a static site in site folder
+      - caddy_data:/data
+      - caddy_conf:/config
 volumes:
 volumes:
+  caddy_data: {}
+  caddy_conf: {}
   sqldata: {}
   sqldata: {}
   dnsconfig: {}
   dnsconfig: {}
+

+ 1 - 0
config/config.go

@@ -73,6 +73,7 @@ type ServerConfig struct {
 	AzureTenant           string `yaml:"azuretenant"`
 	AzureTenant           string `yaml:"azuretenant"`
 	RCE                   string `yaml:"rce"`
 	RCE                   string `yaml:"rce"`
 	Debug                 bool   `yaml:"debug"`
 	Debug                 bool   `yaml:"debug"`
+	Telemetry             string `yaml:"telemetry"`
 }
 }
 
 
 // SQLConfig - Generic SQL Config
 // SQLConfig - Generic SQL Config

+ 31 - 18
controllers/server_util.go

@@ -1,20 +1,33 @@
 package controller
 package controller
 
 
-//func runServerPeerUpdate(network string, shouldPeerUpdate bool) error {
-//	if servercfg.IsClientMode() != "on" {
-//		return nil
-//	}
-//	var currentServerNodeID, err = logic.GetNetworkServerNodeID(network)
-//	if err != nil {
-//		return err
-//	}
-//	var currentServerNode, currErr = logic.GetNodeByID(currentServerNodeID)
-//	if currErr != nil {
-//		return currErr
-//	}
-//	if err = logic.ServerUpdate(&currentServerNode, shouldPeerUpdate); err != nil {
-//		logger.Log(1, "server node:", currentServerNode.ID, "failed update")
-//		return err
-//	}
-//	return nil
-//}
+import (
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/servercfg"
+	"github.com/gravitl/netmaker/serverctl"
+)
+
+func runServerPeerUpdate(network string, shouldPeerUpdate bool) error {
+	if servercfg.Telemetry() == "on" {
+		err := serverctl.TelemetryCheckpoint()
+		if err != nil {
+			logger.Log(1, "failed to send telemetry:", err.Error())
+		}
+	}
+	if servercfg.IsClientMode() != "on" {
+		return nil
+	}
+	var currentServerNodeID, err = logic.GetNetworkServerNodeID(network)
+	if err != nil {
+		return err
+	}
+	var currentServerNode, currErr = logic.GetNodeByID(currentServerNodeID)
+	if currErr != nil {
+		return currErr
+	}
+	if err = logic.ServerUpdate(&currentServerNode, shouldPeerUpdate); err != nil {
+		logger.Log(1, "server node:", currentServerNode.ID, "failed update")
+		return err
+	}
+	return nil
+}

+ 31 - 1
database/database.go

@@ -3,9 +3,12 @@ package database
 import (
 import (
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
+	"strings"
 	"time"
 	"time"
 
 
+	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
 )
 )
 
 
@@ -36,6 +39,12 @@ const PEERS_TABLE_NAME = "peers"
 // SERVERCONF_TABLE_NAME
 // SERVERCONF_TABLE_NAME
 const SERVERCONF_TABLE_NAME = "serverconf"
 const SERVERCONF_TABLE_NAME = "serverconf"
 
 
+// SERVER_UUID_TABLE_NAME
+const SERVER_UUID_TABLE_NAME = "serveruuid"
+
+// SERVER_UUID_RECORD_KEY
+const SERVER_UUID_RECORD_KEY = "serveruuid"
+
 // DATABASE_FILENAME - database file name
 // DATABASE_FILENAME - database file name
 const DATABASE_FILENAME = "netmaker.db"
 const DATABASE_FILENAME = "netmaker.db"
 
 
@@ -105,7 +114,8 @@ func InitializeDatabase() error {
 		time.Sleep(2 * time.Second)
 		time.Sleep(2 * time.Second)
 	}
 	}
 	createTables()
 	createTables()
-	return nil
+	err := initializeUUID()
+	return err
 }
 }
 
 
 func createTables() {
 func createTables() {
@@ -118,6 +128,7 @@ func createTables() {
 	createTable(INT_CLIENTS_TABLE_NAME)
 	createTable(INT_CLIENTS_TABLE_NAME)
 	createTable(PEERS_TABLE_NAME)
 	createTable(PEERS_TABLE_NAME)
 	createTable(SERVERCONF_TABLE_NAME)
 	createTable(SERVERCONF_TABLE_NAME)
+	createTable(SERVER_UUID_TABLE_NAME)
 	createTable(GENERATED_TABLE_NAME)
 	createTable(GENERATED_TABLE_NAME)
 }
 }
 
 
@@ -184,6 +195,25 @@ func FetchRecords(tableName string) (map[string]string, error) {
 	return getCurrentDB()[FETCH_ALL].(func(string) (map[string]string, error))(tableName)
 	return getCurrentDB()[FETCH_ALL].(func(string) (map[string]string, error))(tableName)
 }
 }
 
 
+// initializeUUID - create a UUID record for server if none exists
+func initializeUUID() error {
+	records, err := FetchRecords(SERVER_UUID_TABLE_NAME)
+	if err != nil {
+		if !strings.Contains("could not find any records", err.Error()) {
+			return err
+		}
+	} else if len(records) > 0 {
+		return nil
+	}
+	telemetry := models.Telemetry{UUID: uuid.NewString()}
+	telJSON, err := json.Marshal(telemetry)
+	if err != nil {
+		return err
+	}
+
+	return Insert(SERVER_UUID_RECORD_KEY, string(telJSON), SERVER_UUID_TABLE_NAME)
+}
+
 // CloseDB - closes a database gracefully
 // CloseDB - closes a database gracefully
 func CloseDB() {
 func CloseDB() {
 	getCurrentDB()[CLOSE_DB].(func())()
 	getCurrentDB()[CLOSE_DB].(func())()

BIN
docs/_build/doctrees/api.doctree


BIN
docs/_build/doctrees/architecture.doctree


BIN
docs/_build/doctrees/client-installation.doctree


BIN
docs/_build/doctrees/environment.pickle


BIN
docs/_build/doctrees/server-installation.doctree


BIN
docs/_build/doctrees/support.doctree


BIN
docs/_build/doctrees/troubleshoot.doctree


+ 59 - 47
docs/_build/html/_sources/api.rst.txt

@@ -17,8 +17,11 @@ API calls must be authenticated via a header of  the format  `-H "Authorization:
 
 
 Format of Calls for Curl
 Format of Calls for Curl
 ========================
 ========================
-Requests take the format of `curl -H "Authorization: Bearer <YOUR_SECRET_KEY>" -H 'Content-Type: application/json' localhost:8081/api/path/to/endpoint`
+Requests take the format of 
 
 
+.. code-block::
+
+    curl -H "Authorization: Bearer <YOUR_SECRET_KEY>" -H 'Content-Type: application/json' localhost:8081/api/path/to/endpoint
 
 
 API Documentation
 API Documentation
 =================
 =================
@@ -41,18 +44,21 @@ Networks API
   
   
 Networks API Call Examples
 Networks API Call Examples
 --------------------------  
 --------------------------  
-  
-**Get All Networks:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks | jq`
 
 
-**Create Network:** `curl -d '{"addressrange":"10.70.0.0/16","netid":"skynet"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks`
+.. code-block::
+
+    Get All Networks: curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks | jq
 
 
-**Get Network:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet | jq`
+    Create Network: curl -d '{"addressrange":"10.70.0.0/16","netid":"skynet"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks
 
 
-**Update Network:** `curl -X PUT -d '{"displayname":"my-house"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet`
+    Get Network: curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet | jq
 
 
-**Delete Network:** `curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet`
+    Update Network: curl -X PUT -d '{"displayname":"my-house"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet
+
+    Delete Network: curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet
+
+    Cycle PublicKeys on all Nodes: curl -X POST -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keyupdate
 
 
-**Cycle PublicKeys on all Nodes:** `curl -X POST -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keyupdate`
 
 
 Access Keys API
 Access Keys API
 ---------------
 ---------------
@@ -66,13 +72,15 @@ Access Keys API
   
   
 Access Keys API Call Examples
 Access Keys API Call Examples
 -----------------------------
 -----------------------------
-   
-**Get All Keys:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys | jq`
-  
-**Create Key:** `curl -d '{"uses":10,"name":"mykey"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet/keys`
-  
-**Delete Key:** `curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys/mykey`
-  
+
+.. code-block::
+
+    Get All Keys: curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys | jq
+    
+    Create Key: curl -d '{"uses":10,"name":"mykey"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet/keys
+    
+    Delete Key: curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys/mykey
+
     
     
 Nodes API
 Nodes API
 ---------
 ---------
@@ -104,29 +112,31 @@ Nodes API
   
   
 Nodes API Call Examples
 Nodes API Call Examples
 ----------------------- 
 ----------------------- 
-  
-**Get All Nodes:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes | jq`
-  
-**Get Network Nodes:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet | jq`
+
+.. code-block::
+
+    Get All Nodes: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes | jq
     
     
-**Create Node:** `curl  -d  '{ "endpoint": 100.200.100.200, "publickey": aorijqalrik3ajflaqrdajhkr,"macaddress": "8c:90:b5:06:f1:d9","password": "reallysecret","localaddress": "172.16.16.1","accesskey": "aA3bVG0rnItIRXDx","listenport": 6400}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet`
+    Get Network Nodes: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet | jq
+        
+    Create Node: curl  -d  '{ "endpoint": 100.200.100.200, "publickey": aorijqalrik3ajflaqrdajhkr,"macaddress": "8c:90:b5:06:f1:d9","password": "reallysecret","localaddress": "172.16.16.1","accesskey": "aA3bVG0rnItIRXDx","listenport": 6400}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet
+        
+    Get Node: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet/{macaddress} | jq  
     
     
-**Get Node:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet/{macaddress} | jq`  
-  
-**Update Node:** `curl -X PUT -d '{"name":"laptop1"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9`
-  
-**Delete Node:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/skynet/nodes/8c:90:b5:06:f1:d9`
-  
-**Create a Gateway:** `curl  -d  '{ "rangestring": "172.31.0.0/16", "interface": "eth0"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/creategateway`
-  
-**Delete a Gateway:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/deletegateway`
-  
-**Approve a Pending Node:** `curl -X POST -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/approve`
-  
-**Get Last Modified Date (Last Modified Node in Network):** `curl -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/adm/skynet/lastmodified`
+    Update Node: curl -X PUT -d '{"name":"laptop1"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9
+    
+    Delete Node: curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/skynet/nodes/8c:90:b5:06:f1:d9
+    
+    Create a Gateway: curl  -d  '{ "rangestring": "172.31.0.0/16", "interface": "eth0"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/creategateway
+    
+    Delete a Gateway: curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/deletegateway
+    
+    Approve a Pending Node: curl -X POST -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/approve
+    
+    Get Last Modified Date (Last Modified Node in Network): curl -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/adm/skynet/lastmodified
+
+    Authenticate: curl -d  '{"macaddress": "8c:90:b5:06:f1:d9", "password": "YOUR_PASSWORD"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate
 
 
-**Authenticate:** `curl -d  '{"macaddress": "8c:90:b5:06:f1:d9", "password": "YOUR_PASSWORD"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate`
-  
 
 
 Users API
 Users API
 -----------------------
 -----------------------
@@ -148,19 +158,21 @@ Users API
   
   
 Users API Calls Examples
 Users API Calls Examples
 ------------------------
 ------------------------
-  
-**Get User:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/{username} | jq`
 
 
-**Update User:** `curl -X PUT -d '{"password":"noonewillguessthis"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}`
-  
-**Delete User:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}`
-  
-**Check for Admin User:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/adm/hasadmin`
-  
-**Create Admin User:** `curl -d '{ "username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/adm/createadmin`
-   
-**Authenticate:** `curl -d  '{"username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate`
-  
+.. code-block::
+
+    Get User: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/{username} | jq
+
+    Update User: curl -X PUT -d '{"password":"noonewillguessthis"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}
+    
+    Delete User: curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}
+    
+    Check for Admin User: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/adm/hasadmin
+    
+    Create Admin User: curl -d '{ "username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/adm/createadmin
+    
+    Authenticate: curl -d  '{"username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate
+
 
 
 Server Management API
 Server Management API
 ---------------------
 ---------------------

+ 14 - 4
docs/_build/html/_sources/architecture.rst.txt

@@ -47,7 +47,7 @@ Netmaker
 
 
 Netmaker is a platform built off of WireGuard which enables users to create mesh networks between their devices. Netmaker can create both full and partial mesh networks depending on the use case.
 Netmaker is a platform built off of WireGuard which enables users to create mesh networks between their devices. Netmaker can create both full and partial mesh networks depending on the use case.
 
 
-When we refer to Netmaker in aggregate, we are typically referring to Netmaker and the netclient, as well as other supporting services such as CoreDNS, rqlite, and UI webserver.
+When we refer to Netmaker in aggregate, we are typically referring to Netmaker and the netclient, as well as other supporting services such as CoreDNS, rqlite, and UI webserver. There is also almost always a proxy server / LB, which is typically Caddy.
 
 
 From an end user perspective, they typically interact with the Netmaker UI, or even just run the install script for the netclient on their devices. The other components run in the background invisibly. 
 From an end user perspective, they typically interact with the Netmaker UI, or even just run the install script for the netclient on their devices. The other components run in the background invisibly. 
 
 
@@ -58,14 +58,14 @@ Node
 
 
 A machine in a Netmaker network, which is managed by the Netclient, is referred to as a Node, as you will see in the UI. A Node can be a VM, a bare metal server, a desktop computer, an IoT device, or any other number of internet-connected machines on which the netclient is installed. A node is simply an endpoint in the network, which can send traffic to all the other nodes, and receive traffic from all of the other nodes.
 A machine in a Netmaker network, which is managed by the Netclient, is referred to as a Node, as you will see in the UI. A Node can be a VM, a bare metal server, a desktop computer, an IoT device, or any other number of internet-connected machines on which the netclient is installed. A node is simply an endpoint in the network, which can send traffic to all the other nodes, and receive traffic from all of the other nodes.
 
 
-systemd
+SystemD
 -------
 -------
 
 
-systemd is a system service manager for a wide array of Linux operating systems. Not all Linux distributions have adopted systemd, but, for better or worse, it has become a fairly common standard in the Linux world. That said, any non-Linux operating system will not have systemd, and many Linux/Unix distributionshave alternative system service managers.
+SystemD is a system service manager for a wide array of Linux operating systems. Not all Linux distributions have adopted systemd, but, for better or worse, it has become a fairly common standard in the Linux world. That said, any non-Linux operating system will not have systemd, and many Linux/Unix distributionshave alternative system service managers.
 
 
 Netmaker's netclient, the agent which controls networking on all nodes, can be run as a CLI or as a system daemon. On Linux, it runs as a daemon by default, and this requires systemd. As Netmaker evolves, systemd will become just one of the possible service management options, allowing the netclient to be run on a wider array of devices. However, for the time being, the netclient should be run "unmanaged" (netclient join -daemon=off) on systems that do not run systemd, and some other method can be used like a cron job or custom script.
 Netmaker's netclient, the agent which controls networking on all nodes, can be run as a CLI or as a system daemon. On Linux, it runs as a daemon by default, and this requires systemd. As Netmaker evolves, systemd will become just one of the possible service management options, allowing the netclient to be run on a wider array of devices. However, for the time being, the netclient should be run "unmanaged" (netclient join -daemon=off) on systems that do not run systemd, and some other method can be used like a cron job or custom script.
 
 
-As of 0.8, Mac and Windows are supported. On these operating systems, netclient launches the daemon using LaunchD and Windows Service, respectively, as opposed to systemd.
+As of 0.8, Mac and Windows are supported. On these operating systems, netclient launches the daemon using LaunchD and Windows Service, respectively, as opposed to SystemD.
 
 
 Components
 Components
 ===========
 ===========
@@ -85,6 +85,7 @@ These modes include client mode and dns mode. Either of these can be disabled bu
 
 
 The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.
 The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.
 
 
+The components of the server are usually proxied via Caddy, or an alternative like Nginx and Traefik. The proxy handles SSL certificates to secure traffic, and routes to the UI, API, and gRPC server.
 
 
 Netclient
 Netclient
 ----------------
 ----------------
@@ -124,6 +125,15 @@ CoreDNS
 
 
 Netmaker allows users to provide and manage Private DNS for their nodes. This requires a nameserver, and CoreDNS is the chosen nameserver. CoreDNS is lightweight and extensible. CoreDNS loads dns settings from a simple file, managed by Netmaker, and serves out DNS info for managed nodes. DNS can be tricky, and DNS management is currently only supported on a small set of devices, specifically those running systemd-resolved. However, the Netmaker CoreDNS instance can be added manually as a nameserver to other devices. DNS mode can also be turned off.
 Netmaker allows users to provide and manage Private DNS for their nodes. This requires a nameserver, and CoreDNS is the chosen nameserver. CoreDNS is lightweight and extensible. CoreDNS loads dns settings from a simple file, managed by Netmaker, and serves out DNS info for managed nodes. DNS can be tricky, and DNS management is currently only supported on a small set of devices, specifically those running systemd-resolved. However, the Netmaker CoreDNS instance can be added manually as a nameserver to other devices. DNS mode can also be turned off.
 
 
+Caddy
+-------
+
+Caddy is the default proxy for Netmaker if you set it up via Quick Start. Caddy is an extremely simple and docker-friendly proxy, which can be compared to Nginx, Traefik, or HAProxy. We use Caddy by default because of the ease of management, and integration with gRPC. A typical setup for Nginx might take dozens of lines of code, and we need to request and manage SSL certificates separately.
+
+Caddy handles all these things automatically in very few lines of code. You can see our default "Caddyfile" here, which is fed to the container and has all the configuration necessary to configure the proxy for our app:
+
+https://github.com/gravitl/netmaker/blob/master/docker/Caddyfile
+
 External Client
 External Client
 ----------------
 ----------------
 
 

+ 23 - 0
docs/_build/html/_sources/client-installation.rst.txt

@@ -30,6 +30,29 @@ Windows will by default have firewall rules that prevent inbound connections. If
 
 
 If you want to allow all peers access, but do not want to configure firewall rules for all peers, you can configure access for one peer, and set it as a Relay Server.
 If you want to allow all peers access, but do not want to configure firewall rules for all peers, you can configure access for one peer, and set it as a Relay Server.
 
 
+Running the install script
+----------------------------
+
+Some file locations have issues running the install script, such as running from the root C:/ folder. Users have noted the following locations work well for running the install powershell script:
+
+- `C:/Program Files/wireguard`
+- `C:/Windows/System32`
+
+Running netclient commands
+----------------------------
+
+If running the netclient manually ("netclient join", "netclient checkin", "netclient pull") it should be run from outside of the installed directory, which will be either:
+
+- `C:/Program Files/netclient`
+- `C:/ProgramData/netclient`
+
+It is better to call it from a different directory.
+
+High CPU Utilization
+--------------------------
+
+With some versions of WireGuard on Windows, high CPU utilization has been found with the netclient. This is typically due to interaction with the WireGuard GUI component (app). If you're experiencing high CPU utilization, close the WireGuard app. WireGuard will still be running, but the CPU usage should go back down to normal.
+
 Notes on OpenWRT
 Notes on OpenWRT
 ===========================
 ===========================
 
 

+ 52 - 8
docs/_build/html/_sources/server-installation.rst.txt

@@ -143,9 +143,26 @@ RCE:
 
 
     **Description:** The server enables you to set PostUp and PostDown commands for nodes, which is standard for WireGuard with wg-quick, but is also **Remote Code Execution**, which is a critical vulnerability if the server is exploited. Because of this, it's turned off by default, but if turned on, PostUp and PostDown become editable.
     **Description:** The server enables you to set PostUp and PostDown commands for nodes, which is standard for WireGuard with wg-quick, but is also **Remote Code Execution**, which is a critical vulnerability if the server is exploited. Because of this, it's turned off by default, but if turned on, PostUp and PostDown become editable.
 
 
+SERVER_GRPC_WIREGUARD
+    **Depreciated:** no longer in use
+
+DISPLAY_KEYS
+    **Default:** "on"
+
+    **Description:** If "on", will allow you to always show the key values of "access keys". This could be considered a vulnerability, so if turned "off", will only display key values once, and it is up to the users to store the key values locally.
+
+NODE_ID
+    **Default:** <system mac addres>
+
+    **Description:** This setting is used for HA configurations of the server, to identify between different servers. Nodes are given ID's like netmaker-1, netmaker-2, and netmaker-3. If the server is not HA, there is no reason to set this field.
+
+TELEMETRY
+    **Default:** "on"
+
+    **Description:** If "on", the server will send anonymous telemetry data once daily, which is used to improve the product. Data sent includes counts (integer values) for the number of nodes, types of nodes, users, and networks. It also sends the version of the server.
 
 
 Config File Reference
 Config File Reference
-----------------------
+-----------------------
 A config file may be placed under config/environments/<env-name>.yml. To read this file at runtime, provide the environment variable NETMAKER_ENV at runtime. For instance, dev.yml paired with ENV=dev. Netmaker will load the specified Config file. This allows you to store and manage configurations for different environments. Below is a reference Config File you may use.
 A config file may be placed under config/environments/<env-name>.yml. To read this file at runtime, provide the environment variable NETMAKER_ENV at runtime. For instance, dev.yml paired with ENV=dev. Netmaker will load the specified Config file. This allows you to store and manage configurations for different environments. Below is a reference Config File you may use.
 
 
 .. literalinclude:: ../config/environments/dev.yaml
 .. literalinclude:: ../config/environments/dev.yaml
@@ -159,6 +176,20 @@ All environment variables and options are enabled in this file. It is the equiva
 .. literalinclude:: ../compose/docker-compose.reference.yml
 .. literalinclude:: ../compose/docker-compose.reference.yml
   :language: YAML
   :language: YAML
 
 
+Available docker-compose files
+---------------------------------
+
+The default options for docker-compose can be found here: https://github.com/gravitl/netmaker/tree/master/compose
+
+The following is a brief description of each:
+
+- `docker-compose.contained.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.contained.yml>`_ - This is the default docker-compose, used in the quick start and deployment script in the README on GitHub. It deploys Netmaker with all options included (Caddy and CoreDNS) and has "self-contained" netclients, meaning they do not affect host networking.
+- `docker-compose.coredns.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.coredns.yml>`_ - This is a simple compose used to spin up a standalone CoreDNS server. Can be useful if, for instance, you are unning Netmaker on baremetal but need CoreDNS.
+- `docker-compose.hostnetwork.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.hostnetwork.yml>`_ - This is similar to the docker-compose.contained.yml but with a key difference: it has advanced permissions and mounts host volumes to control networking on the host level.
+- `docker-compose.nocaddy.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.nocaddy.yml>`_ -= This is the same as docker-compose.contained.yml but without Caddy, in case you need to use a different proxy like Nginx, Traefik, or HAProxy.
+- `docker-compose.nodns.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.nodns.yml>`_ - This is the same as docker-compose.contained.yml but without CoreDNS, in which case you will not have the Private DNS feature.
+- `docker-compose.reference.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.reference.yml>`_ - This is the same as docker-compose.contained.yml but with all variable options on display and annotated (it's what we show right above this section). Use this to determine which variables you should add or change in your configuration.
+- `docker-compose.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.yml>`_ - This is a renamed docker-compose.contained.yml. It is meant only to act as a placeholder for what we consider the "primary" docker-compose that users should work with.
 
 
 DNS Mode Setup
 DNS Mode Setup
 ====================================
 ====================================
@@ -230,18 +261,21 @@ This template is equivalent but omits CoreDNS.
 Linux Install without Docker
 Linux Install without Docker
 =============================
 =============================
 
 
-Most systems support Docker, but some do not. In such environments, there are many options for installing Netmaker. Netmaker is available as a binary file, and there is a zip file of the Netmaker UI static HTML on GitHub. Beyond the UI and Server, you need to install MongoDB and CoreDNS (optional). 
-
-To start, we recommend following the Nginx instructions in the :doc:`Quick Install <./quick-start>` guide to enable SSL for your environment.
+Most systems support Docker, but some do not. In such environments, there are many options for installing Netmaker. Netmaker is available as a binary file, and there is a zip file of the Netmaker UI static HTML on GitHub. Beyond the UI and Server, you may want to optionally install a database (sqlite is embedded, rqlite or postgres are supported) and CoreDNS (also optional). 
 
 
 Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.
 Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.
 
 
-rqlite Setup
-----------------
+Database Setup (optional)
+--------------------------
+
+You can run the netmaker binary standalone and it will run an embedded sqlite server. Data goes in the data/ directory. Optionally, you can run PostgreSQL or rqlite. Instructions for rqlite are below.
+
 1. Install rqlite on your server: https://github.com/rqlite/rqlite
 1. Install rqlite on your server: https://github.com/rqlite/rqlite
 
 
 2. Run rqlite: rqlited -node-id 1 ~/node.1
 2. Run rqlite: rqlited -node-id 1 ~/node.1
 
 
+If using rqlite or postgres, you must change the DATABASE environment/config variable and enter connection details.
+
 Server Setup
 Server Setup
 -------------
 -------------
 1. **Run the install script:** 
 1. **Run the install script:** 
@@ -271,8 +305,18 @@ The following uses Nginx as an http server. You may alternatively use Apache or
   sudo sh -c 'BACKEND_URL=http://<YOUR BACKEND API URL>:PORT /usr/share/nginx/html/generate_config_js.sh >/usr/share/nginx/html/config.js'
   sudo sh -c 'BACKEND_URL=http://<YOUR BACKEND API URL>:PORT /usr/share/nginx/html/generate_config_js.sh >/usr/share/nginx/html/config.js'
   sudo systemctl start nginx
   sudo systemctl start nginx
 
 
-CoreDNS Setup
-----------------
+CoreDNS Setup (optional)
+----------------------------
+
+CoreDNS is only required if you want private DNS features. Once installed, you must set the CoreDNS variables in the env settings of the server.
+
+See https://coredns.io/manual/toc/#installation
+
+Proxy / Load Balancer
+------------------------
+
+You will need to proxy connections to your UI and Server. By default the ports are 8081, 8082, and 50051 (grpc). This proxy should handle SSL certificates. We recommend Caddy or Nginx (you can follow the Nginx guide in these docs). The proxy must be able to handle gRPC connections.
+
 
 
 .. _KubeInstall:
 .. _KubeInstall:
 
 

+ 27 - 0
docs/_build/html/_sources/support.rst.txt

@@ -39,6 +39,33 @@ We believe the SSPL lets most people run the project the way they want, for both
 
 
 If you believe the SSPL will negatively impact your ability to use the project, please do not hesitate to reach out.
 If you believe the SSPL will negatively impact your ability to use the project, please do not hesitate to reach out.
 
 
+Telemetry
+==============
+
+As of v0.10.0, Netmaker collects "opt-out" telemetry data. To opt out, simply set "TELEMETRY=off" in your docker-compose file.
+
+Please consider participating in telemetry, as it helps us focus on the features and bug fixes which are most useful to users. Netmaker is a broad platform, and without this data, it is difficult to know where the team should spend its limited resources.
+
+The following is the full list of telemetry data we collect. Besides "Server Version" all data is simply an integer count:
+
+- Randomized server ID
+- Count of nodes
+- Count of "non-server" nodes
+- Count of external clients
+- Count of networks
+- Count of users
+- Count of linux nodes
+- Count of freebsd nodes
+- Count of macos nodes
+- Count of windows nodes
+- Count of docker nodes
+- Count of k8s nodes
+- Server version
+
+We use  `PostHog <https://https://posthog.com/>`_, an open source and trusted framework for telemetry data.
+
+To look at exactly we collect telemetry, you can view the source code under serverctl/telemetry.go: https://github.com/gravitl/netmaker/blob/master/serverctl/telemetry.go
+
 Contact
 Contact
 ===========
 ===========
 If you need help, try the discord or open a GitHub ticket.
 If you need help, try the discord or open a GitHub ticket.

+ 7 - 0
docs/_build/html/_sources/troubleshoot.rst.txt

@@ -29,6 +29,13 @@ Common Issues
 Server
 Server
 -------
 -------
 
 
+**How do I use a private address from the Netmaker Server? How do I contact nodes using their private addresses from the server?**
+  Default nodes appear in each network with the "netmaker" name. These nodes are created by, and attached to, the server. The server is contained in docker, meaning these clients are also contained in docker. Their networking stack is also contained in docker. The "netmaker" nodes are meant to function as network utilities. They assist with UDP Hole Punching and can run Relays, Egress, and Ingress. However, they are meant to stay contained in the server. They do not touch the host networking stack.
+
+  If you want to give the physical server / VM a private IP in the netmaker network, you must deploy an **additional** node using the standard netclient. The only note here is that the server consumes ports 51821-51831, so you will need to give it a port outside this range, e.x. `./netclient join <token> --port 51835`.
+
+  One a netclient is deployed to the underlying server/VM, you will be able to use the private address to reach other nodes from the host, or to reach the server over the private network.
+
 **I upgraded from 0.7 to 0.8 and now I dont have any data in my server!**
 **I upgraded from 0.7 to 0.8 and now I dont have any data in my server!**
   In 0.8, sqlite becomes the default database. If you were running with rqlite, you must set the DATABASE environment variable to rqlite in order to continue using rqlite.
   In 0.8, sqlite becomes the default database. If you were running with rqlite, you must set the DATABASE environment variable to rqlite in order to continue using rqlite.
 
 

+ 60 - 27
docs/_build/html/api.html

@@ -489,7 +489,10 @@
 
 
 
 
 <h2 id="format-of-calls-for-curl">Format of Calls for Curl<a class="headerlink" href="#format-of-calls-for-curl" title="Permalink to this headline">¶</a></h2>
 <h2 id="format-of-calls-for-curl">Format of Calls for Curl<a class="headerlink" href="#format-of-calls-for-curl" title="Permalink to this headline">¶</a></h2>
-<p>Requests take the format of <cite>curl -H “Authorization: Bearer &lt;YOUR_SECRET_KEY&gt;” -H ‘Content-Type: application/json’ localhost:8081/api/path/to/endpoint</cite></p>
+<p>Requests take the format of</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer &lt;YOUR_SECRET_KEY&gt;"</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">path</span><span class="o">/</span><span class="n">to</span><span class="o">/</span><span class="n">endpoint</span>
+</pre></div>
+</div>
 
 
 
 
 <h2 id="api-documentation">API Documentation<a class="headerlink" href="#api-documentation" title="Permalink to this headline">¶</a></h2>
 <h2 id="api-documentation">API Documentation<a class="headerlink" href="#api-documentation" title="Permalink to this headline">¶</a></h2>
@@ -504,12 +507,19 @@
 
 
 
 
 <h3 id="networks-api-call-examples">Networks API Call Examples<a class="headerlink" href="#networks-api-call-examples" title="Permalink to this headline">¶</a></h3>
 <h3 id="networks-api-call-examples">Networks API Call Examples<a class="headerlink" href="#networks-api-call-examples" title="Permalink to this headline">¶</a></h3>
-<p><strong>Get All Networks:</strong> <cite>curl -H “Authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/networks | jq</cite></p>
-<p><strong>Create Network:</strong> <cite>curl -d ‘{“addressrange”:”10.70.0.0/16”,”netid”:”skynet”}’ -H “Authorization: Bearer YOUR_SECRET_KEY” -H ‘Content-Type: application/json’ localhost:8081/api/networks</cite></p>
-<p><strong>Get Network:</strong> <cite>curl -H “Authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/networks/skynet | jq</cite></p>
-<p><strong>Update Network:</strong> <cite>curl -X PUT -d ‘{“displayname”:”my-house”}’ -H “Authorization: Bearer YOUR_SECRET_KEY” -H ‘Content-Type: application/json’ localhost:8081/api/networks/skynet</cite></p>
-<p><strong>Delete Network:</strong> <cite>curl -X DELETE -H “Authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/networks/skynet</cite></p>
-<p><strong>Cycle PublicKeys on all Nodes:</strong> <cite>curl -X POST -H “Authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/networks/skynet/keyupdate</cite></p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Get</span> <span class="n">All</span> <span class="n">Networks</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span> <span class="o">|</span> <span class="n">jq</span>
+
+<span class="n">Create</span> <span class="n">Network</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">d</span> <span class="s1">'{"addressrange":"10.70.0.0/16","netid":"skynet"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span>
+
+<span class="n">Get</span> <span class="n">Network</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span><span class="o">/</span><span class="n">skynet</span> <span class="o">|</span> <span class="n">jq</span>
+
+<span class="n">Update</span> <span class="n">Network</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">PUT</span> <span class="o">-</span><span class="n">d</span> <span class="s1">'{"displayname":"my-house"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span><span class="o">/</span><span class="n">skynet</span>
+
+<span class="n">Delete</span> <span class="n">Network</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">DELETE</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span><span class="o">/</span><span class="n">skynet</span>
+
+<span class="n">Cycle</span> <span class="n">PublicKeys</span> <span class="n">on</span> <span class="nb">all</span> <span class="n">Nodes</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">POST</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="n">keyupdate</span>
+</pre></div>
+</div>
 
 
 
 
 <h3 id="access-keys-api">Access Keys API<a class="headerlink" href="#access-keys-api" title="Permalink to this headline">¶</a></h3>
 <h3 id="access-keys-api">Access Keys API<a class="headerlink" href="#access-keys-api" title="Permalink to this headline">¶</a></h3>
@@ -519,9 +529,13 @@
 
 
 
 
 <h3 id="access-keys-api-call-examples">Access Keys API Call Examples<a class="headerlink" href="#access-keys-api-call-examples" title="Permalink to this headline">¶</a></h3>
 <h3 id="access-keys-api-call-examples">Access Keys API Call Examples<a class="headerlink" href="#access-keys-api-call-examples" title="Permalink to this headline">¶</a></h3>
-<p><strong>Get All Keys:</strong> <cite>curl -H “Authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/networks/skynet/keys | jq</cite></p>
-<p><strong>Create Key:</strong> <cite>curl -d ‘{“uses”:10,”name”:”mykey”}’ -H “Authorization: Bearer YOUR_SECRET_KEY” -H ‘Content-Type: application/json’ localhost:8081/api/networks/skynet/keys</cite></p>
-<p><strong>Delete Key:</strong> <cite>curl -X DELETE -H “Authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/networks/skynet/keys/mykey</cite></p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Get</span> <span class="n">All</span> <span class="n">Keys</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="n">keys</span> <span class="o">|</span> <span class="n">jq</span>
+
+<span class="n">Create</span> <span class="n">Key</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">d</span> <span class="s1">'{"uses":10,"name":"mykey"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="n">keys</span>
+
+<span class="n">Delete</span> <span class="n">Key</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">DELETE</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">networks</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="n">keys</span><span class="o">/</span><span class="n">mykey</span>
+</pre></div>
+</div>
 
 
 
 
 <h3 id="nodes-api">Nodes API<a class="headerlink" href="#nodes-api" title="Permalink to this headline">¶</a></h3>
 <h3 id="nodes-api">Nodes API<a class="headerlink" href="#nodes-api" title="Permalink to this headline">¶</a></h3>
@@ -540,17 +554,29 @@
 
 
 
 
 <h3 id="nodes-api-call-examples">Nodes API Call Examples<a class="headerlink" href="#nodes-api-call-examples" title="Permalink to this headline">¶</a></h3>
 <h3 id="nodes-api-call-examples">Nodes API Call Examples<a class="headerlink" href="#nodes-api-call-examples" title="Permalink to this headline">¶</a></h3>
-<p><strong>Get All Nodes:</strong> <cite>curl -H “Authorization: Bearer YOUR_SECRET_KEY” http://localhost:8081/api/nodes | jq</cite></p>
-<p><strong>Get Network Nodes:</strong> <cite>curl -H “Authorization: Bearer YOUR_SECRET_KEY” http://localhost:8081/api/nodes/skynet | jq</cite></p>
-<p><strong>Create Node:</strong> <cite>curl  -d  ‘{ “endpoint”: 100.200.100.200, “publickey”: aorijqalrik3ajflaqrdajhkr,”macaddress”: “8c:90:b5:06:f1:d9”,”password”: “reallysecret”,”localaddress”: “172.16.16.1”,”accesskey”: “aA3bVG0rnItIRXDx”,”listenport”: 6400}’ -H ‘Content-Type: application/json’ -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/nodes/skynet</cite></p>
-<p><strong>Get Node:</strong> <cite>curl -H “Authorization: Bearer YOUR_SECRET_KEY” http://localhost:8081/api/nodes/skynet/{macaddress} | jq</cite></p>
-<p><strong>Update Node:</strong> <cite>curl -X PUT -d ‘{“name”:”laptop1”}’ -H ‘Content-Type: application/json’ -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9</cite></p>
-<p><strong>Delete Node:</strong> <cite>curl -X DELETE -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/skynet/nodes/8c:90:b5:06:f1:d9</cite></p>
-<p><strong>Create a Gateway:</strong> <cite>curl  -d  ‘{ “rangestring”: “172.31.0.0/16”, “interface”: “eth0”}’ -H ‘Content-Type: application/json’ -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/creategateway</cite></p>
-<p><strong>Delete a Gateway:</strong> <cite>curl -X DELETE -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/deletegateway</cite></p>
-<p><strong>Approve a Pending Node:</strong> <cite>curl -X POST -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/approve</cite></p>
-<p><strong>Get Last Modified Date (Last Modified Node in Network):</strong> <cite>curl -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/nodes/adm/skynet/lastmodified</cite></p>
-<p><strong>Authenticate:</strong> <cite>curl -d  ‘{“macaddress”: “8c:90:b5:06:f1:d9”, “password”: “YOUR_PASSWORD”}’ -H ‘Content-Type: application/json’ localhost:8081/api/nodes/adm/skynet/authenticate</cite></p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Get</span> <span class="n">All</span> <span class="n">Nodes</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span> <span class="o">|</span> <span class="n">jq</span>
+
+<span class="n">Get</span> <span class="n">Network</span> <span class="n">Nodes</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">skynet</span> <span class="o">|</span> <span class="n">jq</span>
+
+<span class="n">Create</span> <span class="n">Node</span><span class="p">:</span> <span class="n">curl</span>  <span class="o">-</span><span class="n">d</span>  <span class="s1">'{ "endpoint": 100.200.100.200, "publickey": aorijqalrik3ajflaqrdajhkr,"macaddress": "8c:90:b5:06:f1:d9","password": "reallysecret","localaddress": "172.16.16.1","accesskey": "aA3bVG0rnItIRXDx","listenport": 6400}'</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">skynet</span>
+
+<span class="n">Get</span> <span class="n">Node</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="p">{</span><span class="n">macaddress</span><span class="p">}</span> <span class="o">|</span> <span class="n">jq</span>
+
+<span class="n">Update</span> <span class="n">Node</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">PUT</span> <span class="o">-</span><span class="n">d</span> <span class="s1">'{"name":"laptop1"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="mi">8</span><span class="n">c</span><span class="p">:</span><span class="mi">90</span><span class="p">:</span><span class="n">b5</span><span class="p">:</span><span class="mi">06</span><span class="p">:</span><span class="n">f1</span><span class="p">:</span><span class="n">d9</span>
+
+<span class="n">Delete</span> <span class="n">Node</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">DELETE</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="mi">8</span><span class="n">c</span><span class="p">:</span><span class="mi">90</span><span class="p">:</span><span class="n">b5</span><span class="p">:</span><span class="mi">06</span><span class="p">:</span><span class="n">f1</span><span class="p">:</span><span class="n">d9</span>
+
+<span class="n">Create</span> <span class="n">a</span> <span class="n">Gateway</span><span class="p">:</span> <span class="n">curl</span>  <span class="o">-</span><span class="n">d</span>  <span class="s1">'{ "rangestring": "172.31.0.0/16", "interface": "eth0"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="mi">8</span><span class="n">c</span><span class="p">:</span><span class="mi">90</span><span class="p">:</span><span class="n">b5</span><span class="p">:</span><span class="mi">06</span><span class="p">:</span><span class="n">f1</span><span class="p">:</span><span class="n">d9</span><span class="o">/</span><span class="n">creategateway</span>
+
+<span class="n">Delete</span> <span class="n">a</span> <span class="n">Gateway</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">DELETE</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="mi">8</span><span class="n">c</span><span class="p">:</span><span class="mi">90</span><span class="p">:</span><span class="n">b5</span><span class="p">:</span><span class="mi">06</span><span class="p">:</span><span class="n">f1</span><span class="p">:</span><span class="n">d9</span><span class="o">/</span><span class="n">deletegateway</span>
+
+<span class="n">Approve</span> <span class="n">a</span> <span class="n">Pending</span> <span class="n">Node</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">POST</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="mi">8</span><span class="n">c</span><span class="p">:</span><span class="mi">90</span><span class="p">:</span><span class="n">b5</span><span class="p">:</span><span class="mi">06</span><span class="p">:</span><span class="n">f1</span><span class="p">:</span><span class="n">d9</span><span class="o">/</span><span class="n">approve</span>
+
+<span class="n">Get</span> <span class="n">Last</span> <span class="n">Modified</span> <span class="n">Date</span> <span class="p">(</span><span class="n">Last</span> <span class="n">Modified</span> <span class="n">Node</span> <span class="ow">in</span> <span class="n">Network</span><span class="p">):</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">adm</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="n">lastmodified</span>
+
+<span class="n">Authenticate</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">d</span>  <span class="s1">'{"macaddress": "8c:90:b5:06:f1:d9", "password": "YOUR_PASSWORD"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">adm</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="n">authenticate</span>
+</pre></div>
+</div>
 
 
 
 
 <h3 id="users-api">Users API<a class="headerlink" href="#users-api" title="Permalink to this headline">¶</a></h3>
 <h3 id="users-api">Users API<a class="headerlink" href="#users-api" title="Permalink to this headline">¶</a></h3>
@@ -564,12 +590,19 @@
 
 
 
 
 <h3 id="users-api-calls-examples">Users API Calls Examples<a class="headerlink" href="#users-api-calls-examples" title="Permalink to this headline">¶</a></h3>
 <h3 id="users-api-calls-examples">Users API Calls Examples<a class="headerlink" href="#users-api-calls-examples" title="Permalink to this headline">¶</a></h3>
-<p><strong>Get User:</strong> <cite>curl -H “Authorization: Bearer YOUR_SECRET_KEY” http://localhost:8081/api/users/{username} | jq</cite></p>
-<p><strong>Update User:</strong> <cite>curl -X PUT -d ‘{“password”:”noonewillguessthis”}’ -H ‘Content-Type: application/json’ -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/users/{username}</cite></p>
-<p><strong>Delete User:</strong> <cite>curl -X DELETE -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/users/{username}</cite></p>
-<p><strong>Check for Admin User:</strong> <cite>curl -H “Authorization: Bearer YOUR_SECRET_KEY” http://localhost:8081/api/users/adm/hasadmin</cite></p>
-<p><strong>Create Admin User:</strong> <cite>curl -d ‘{ “username”: “smartguy”, “password”: “YOUR_PASS”}’ -H ‘Content-Type: application/json’ -H “authorization: Bearer YOUR_SECRET_KEY” localhost:8081/api/users/adm/createadmin</cite></p>
-<p><strong>Authenticate:</strong> <cite>curl -d  ‘{“username”: “smartguy”, “password”: “YOUR_PASS”}’ -H ‘Content-Type: application/json’ localhost:8081/api/nodes/adm/skynet/authenticate</cite></p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Get</span> <span class="n">User</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">users</span><span class="o">/</span><span class="p">{</span><span class="n">username</span><span class="p">}</span> <span class="o">|</span> <span class="n">jq</span>
+
+<span class="n">Update</span> <span class="n">User</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">PUT</span> <span class="o">-</span><span class="n">d</span> <span class="s1">'{"password":"noonewillguessthis"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">users</span><span class="o">/</span><span class="p">{</span><span class="n">username</span><span class="p">}</span>
+
+<span class="n">Delete</span> <span class="n">User</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="n">DELETE</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">users</span><span class="o">/</span><span class="p">{</span><span class="n">username</span><span class="p">}</span>
+
+<span class="n">Check</span> <span class="k">for</span> <span class="n">Admin</span> <span class="n">User</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"Authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">users</span><span class="o">/</span><span class="n">adm</span><span class="o">/</span><span class="n">hasadmin</span>
+
+<span class="n">Create</span> <span class="n">Admin</span> <span class="n">User</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">d</span> <span class="s1">'{ "username": "smartguy", "password": "YOUR_PASS"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="o">-</span><span class="n">H</span> <span class="s2">"authorization: Bearer YOUR_SECRET_KEY"</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">users</span><span class="o">/</span><span class="n">adm</span><span class="o">/</span><span class="n">createadmin</span>
+
+<span class="n">Authenticate</span><span class="p">:</span> <span class="n">curl</span> <span class="o">-</span><span class="n">d</span>  <span class="s1">'{"username": "smartguy", "password": "YOUR_PASS"}'</span> <span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8081</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">nodes</span><span class="o">/</span><span class="n">adm</span><span class="o">/</span><span class="n">skynet</span><span class="o">/</span><span class="n">authenticate</span>
+</pre></div>
+</div>
 
 
 
 
 <h3 id="server-management-api">Server Management API<a class="headerlink" href="#server-management-api" title="Permalink to this headline">¶</a></h3>
 <h3 id="server-management-api">Server Management API<a class="headerlink" href="#server-management-api" title="Permalink to this headline">¶</a></h3>

+ 12 - 1
docs/_build/html/architecture.html

@@ -253,6 +253,8 @@
         </li>
         </li>
         <li class="md-nav__item"><a href="#coredns" class="md-nav__link">CoreDNS</a>
         <li class="md-nav__item"><a href="#coredns" class="md-nav__link">CoreDNS</a>
         </li>
         </li>
+        <li class="md-nav__item"><a href="#caddy" class="md-nav__link">Caddy</a>
+        </li>
         <li class="md-nav__item"><a href="#external-client" class="md-nav__link">External Client</a>
         <li class="md-nav__item"><a href="#external-client" class="md-nav__link">External Client</a>
         </li></ul>
         </li></ul>
             </nav>
             </nav>
@@ -473,6 +475,8 @@
         </li>
         </li>
         <li class="md-nav__item"><a href="#coredns" class="md-nav__link">CoreDNS</a>
         <li class="md-nav__item"><a href="#coredns" class="md-nav__link">CoreDNS</a>
         </li>
         </li>
+        <li class="md-nav__item"><a href="#caddy" class="md-nav__link">Caddy</a>
+        </li>
         <li class="md-nav__item"><a href="#external-client" class="md-nav__link">External Client</a>
         <li class="md-nav__item"><a href="#external-client" class="md-nav__link">External Client</a>
         </li></ul>
         </li></ul>
             </nav>
             </nav>
@@ -518,7 +522,7 @@
 
 
 <h3 id="netmaker">Netmaker<a class="headerlink" href="#netmaker" title="Permalink to this headline">¶</a></h3>
 <h3 id="netmaker">Netmaker<a class="headerlink" href="#netmaker" title="Permalink to this headline">¶</a></h3>
 <p>Netmaker is a platform built off of WireGuard which enables users to create mesh networks between their devices. Netmaker can create both full and partial mesh networks depending on the use case.</p>
 <p>Netmaker is a platform built off of WireGuard which enables users to create mesh networks between their devices. Netmaker can create both full and partial mesh networks depending on the use case.</p>
-<p>When we refer to Netmaker in aggregate, we are typically referring to Netmaker and the netclient, as well as other supporting services such as CoreDNS, rqlite, and UI webserver.</p>
+<p>When we refer to Netmaker in aggregate, we are typically referring to Netmaker and the netclient, as well as other supporting services such as CoreDNS, rqlite, and UI webserver. There is also almost always a proxy server / LB, which is typically Caddy.</p>
 <p>From an end user perspective, they typically interact with the Netmaker UI, or even just run the install script for the netclient on their devices. The other components run in the background invisibly.</p>
 <p>From an end user perspective, they typically interact with the Netmaker UI, or even just run the install script for the netclient on their devices. The other components run in the background invisibly.</p>
 <p>Netmaker does a lot of work to set configurations for you, so that you don’t have to. This includes things like WireGuard ports, endpoints, public IPs, keys, and peers. Netmaker works to abstract away as much of the network management as possible, so that you can just click to create a network, and click to add a machine to a network. That said, every machine (node) is different, and may require special configuration. That is why, while Netmaker sets practical default settings, everything within Netmaker is fully configurable.</p>
 <p>Netmaker does a lot of work to set configurations for you, so that you don’t have to. This includes things like WireGuard ports, endpoints, public IPs, keys, and peers. Netmaker works to abstract away as much of the network management as possible, so that you can just click to create a network, and click to add a machine to a network. That said, every machine (node) is different, and may require special configuration. That is why, while Netmaker sets practical default settings, everything within Netmaker is fully configurable.</p>
 
 
@@ -543,6 +547,7 @@
 <p>Most server settings are configurable via a config file, or by environment variables (which take precedence). If the server finds neither of these, it sets sensible defaults, including things like the server’s reachable IP, ports, and which “modes” to run in.</p>
 <p>Most server settings are configurable via a config file, or by environment variables (which take precedence). If the server finds neither of these, it sets sensible defaults, including things like the server’s reachable IP, ports, and which “modes” to run in.</p>
 <p>These modes include client mode and dns mode. Either of these can be disabled but are enabled by default. Client mode allows you to treat the Netmaker host machine (operating system) as a network Node, installing the netclient and controlling the host network. DNS mode has the server write config settings for CoreDNS, a separate component and nameserver, which picks up the config settings to manage node DNS.</p>
 <p>These modes include client mode and dns mode. Either of these can be disabled but are enabled by default. Client mode allows you to treat the Netmaker host machine (operating system) as a network Node, installing the netclient and controlling the host network. DNS mode has the server write config settings for CoreDNS, a separate component and nameserver, which picks up the config settings to manage node DNS.</p>
 <p>The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.</p>
 <p>The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.</p>
+<p>The components of the server are usually proxied via Caddy, or an alternative like Nginx and Traefik. The proxy handles SSL certificates to secure traffic, and routes to the UI, API, and gRPC server.</p>
 
 
 
 
 <h3 id="netclient">Netclient<a class="headerlink" href="#netclient" title="Permalink to this headline">¶</a></h3>
 <h3 id="netclient">Netclient<a class="headerlink" href="#netclient" title="Permalink to this headline">¶</a></h3>
@@ -569,6 +574,12 @@
 <p>Netmaker allows users to provide and manage Private DNS for their nodes. This requires a nameserver, and CoreDNS is the chosen nameserver. CoreDNS is lightweight and extensible. CoreDNS loads dns settings from a simple file, managed by Netmaker, and serves out DNS info for managed nodes. DNS can be tricky, and DNS management is currently only supported on a small set of devices, specifically those running systemd-resolved. However, the Netmaker CoreDNS instance can be added manually as a nameserver to other devices. DNS mode can also be turned off.</p>
 <p>Netmaker allows users to provide and manage Private DNS for their nodes. This requires a nameserver, and CoreDNS is the chosen nameserver. CoreDNS is lightweight and extensible. CoreDNS loads dns settings from a simple file, managed by Netmaker, and serves out DNS info for managed nodes. DNS can be tricky, and DNS management is currently only supported on a small set of devices, specifically those running systemd-resolved. However, the Netmaker CoreDNS instance can be added manually as a nameserver to other devices. DNS mode can also be turned off.</p>
 
 
 
 
+<h3 id="caddy">Caddy<a class="headerlink" href="#caddy" title="Permalink to this headline">¶</a></h3>
+<p>Caddy is the default proxy for Netmaker if you set it up via Quick Start. Caddy is an extremely simple and docker-friendly proxy, which can be compared to Nginx, Traefik, or HAProxy. We use Caddy by default because of the ease of management, and integration with gRPC. A typical setup for Nginx might take dozens of lines of code, and we need to request and manage SSL certificates separately.</p>
+<p>Caddy handles all these things automatically in very few lines of code. You can see our default “Caddyfile” here, which is fed to the container and has all the configuration necessary to configure the proxy for our app:</p>
+<p><a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/docker/Caddyfile">https://github.com/gravitl/netmaker/blob/master/docker/Caddyfile</a></p>
+
+
 <h3 id="external-client">External Client<a class="headerlink" href="#external-client" title="Permalink to this headline">¶</a></h3>
 <h3 id="external-client">External Client<a class="headerlink" href="#external-client" title="Permalink to this headline">¶</a></h3>
 <p>The external client is simply a manually configured WireGuard connection to your network, which Netmaker helps to manage.</p>
 <p>The external client is simply a manually configured WireGuard connection to your network, which Netmaker helps to manage.</p>
 <p>Most machines can run WireGuard. It is fairly simple to set up a WireGuard connection to a single endpoint. It is setting up mesh networks and other topologies like site-to-site which becomes complicated.</p>
 <p>Most machines can run WireGuard. It is fairly simple to set up a WireGuard connection to a single endpoint. It is setting up mesh networks and other topologies like site-to-site which becomes complicated.</p>

+ 39 - 2
docs/_build/html/client-installation.html

@@ -292,7 +292,15 @@
               <ul class="md-nav__list">
               <ul class="md-nav__list">
         <li class="md-nav__item"><a href="#introduction-to-netclient" class="md-nav__link">Introduction to Netclient</a>
         <li class="md-nav__item"><a href="#introduction-to-netclient" class="md-nav__link">Introduction to Netclient</a>
         </li>
         </li>
-        <li class="md-nav__item"><a href="#notes-on-windows" class="md-nav__link">Notes on Windows</a>
+        <li class="md-nav__item"><a href="#notes-on-windows" class="md-nav__link">Notes on Windows</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#running-the-install-script" class="md-nav__link">Running the install script</a>
+        </li>
+        <li class="md-nav__item"><a href="#running-netclient-commands" class="md-nav__link">Running netclient commands</a>
+        </li>
+        <li class="md-nav__item"><a href="#high-cpu-utilization" class="md-nav__link">High CPU Utilization</a>
+        </li></ul>
+            </nav>
         </li>
         </li>
         <li class="md-nav__item"><a href="#notes-on-openwrt" class="md-nav__link">Notes on OpenWRT</a>
         <li class="md-nav__item"><a href="#notes-on-openwrt" class="md-nav__link">Notes on OpenWRT</a>
         </li>
         </li>
@@ -474,7 +482,15 @@
               <ul class="md-nav__list">
               <ul class="md-nav__list">
         <li class="md-nav__item"><a href="#introduction-to-netclient" class="md-nav__link">Introduction to Netclient</a>
         <li class="md-nav__item"><a href="#introduction-to-netclient" class="md-nav__link">Introduction to Netclient</a>
         </li>
         </li>
-        <li class="md-nav__item"><a href="#notes-on-windows" class="md-nav__link">Notes on Windows</a>
+        <li class="md-nav__item"><a href="#notes-on-windows" class="md-nav__link">Notes on Windows</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#running-the-install-script" class="md-nav__link">Running the install script</a>
+        </li>
+        <li class="md-nav__item"><a href="#running-netclient-commands" class="md-nav__link">Running netclient commands</a>
+        </li>
+        <li class="md-nav__item"><a href="#high-cpu-utilization" class="md-nav__link">High CPU Utilization</a>
+        </li></ul>
+            </nav>
         </li>
         </li>
         <li class="md-nav__item"><a href="#notes-on-openwrt" class="md-nav__link">Notes on OpenWRT</a>
         <li class="md-nav__item"><a href="#notes-on-openwrt" class="md-nav__link">Notes on OpenWRT</a>
         </li>
         </li>
@@ -542,6 +558,27 @@
 <p><code class="docutils literal notranslate"><span class="pre">netsh</span> <span class="pre">advfirewall</span> <span class="pre">firewall</span> <span class="pre">add</span> <span class="pre">rule</span> <span class="pre">name="Allow</span> <span class="pre">from</span> <span class="pre">&lt;peer</span> <span class="pre">private</span> <span class="pre">addr&gt;"</span> <span class="pre">dir=in</span> <span class="pre">action=allow</span> <span class="pre">protocol=ANY</span> <span class="pre">remoteip=&lt;peer</span> <span class="pre">private</span> <span class="pre">addr&gt;</span></code></p>
 <p><code class="docutils literal notranslate"><span class="pre">netsh</span> <span class="pre">advfirewall</span> <span class="pre">firewall</span> <span class="pre">add</span> <span class="pre">rule</span> <span class="pre">name="Allow</span> <span class="pre">from</span> <span class="pre">&lt;peer</span> <span class="pre">private</span> <span class="pre">addr&gt;"</span> <span class="pre">dir=in</span> <span class="pre">action=allow</span> <span class="pre">protocol=ANY</span> <span class="pre">remoteip=&lt;peer</span> <span class="pre">private</span> <span class="pre">addr&gt;</span></code></p>
 <p>If you want to allow all peers access, but do not want to configure firewall rules for all peers, you can configure access for one peer, and set it as a Relay Server.</p>
 <p>If you want to allow all peers access, but do not want to configure firewall rules for all peers, you can configure access for one peer, and set it as a Relay Server.</p>
 
 
+<h3 id="running-the-install-script">Running the install script<a class="headerlink" href="#running-the-install-script" title="Permalink to this headline">¶</a></h3>
+<p>Some file locations have issues running the install script, such as running from the root C:/ folder. Users have noted the following locations work well for running the install powershell script:</p>
+<ul class="simple">
+<li><p><cite>C:/Program Files/wireguard</cite></p></li>
+<li><p><cite>C:/Windows/System32</cite></p></li>
+</ul>
+
+
+<h3 id="running-netclient-commands">Running netclient commands<a class="headerlink" href="#running-netclient-commands" title="Permalink to this headline">¶</a></h3>
+<p>If running the netclient manually (“netclient join”, “netclient checkin”, “netclient pull”) it should be run from outside of the installed directory, which will be either:</p>
+<ul class="simple">
+<li><p><cite>C:/Program Files/netclient</cite></p></li>
+<li><p><cite>C:/ProgramData/netclient</cite></p></li>
+</ul>
+<p>It is better to call it from a different directory.</p>
+
+
+<h3 id="high-cpu-utilization">High CPU Utilization<a class="headerlink" href="#high-cpu-utilization" title="Permalink to this headline">¶</a></h3>
+<p>With some versions of WireGuard on Windows, high CPU utilization has been found with the netclient. This is typically due to interaction with the WireGuard GUI component (app). If you’re experiencing high CPU utilization, close the WireGuard app. WireGuard will still be running, but the CPU usage should go back down to normal.</p>
+
+
 
 
 <h2 id="notes-on-openwrt">Notes on OpenWRT<a class="headerlink" href="#notes-on-openwrt" title="Permalink to this headline">¶</a></h2>
 <h2 id="notes-on-openwrt">Notes on OpenWRT<a class="headerlink" href="#notes-on-openwrt" title="Permalink to this headline">¶</a></h2>
 <p>Deploying on OpenWRT depends a lot on the version of OpenWRT and the hardware being used. If the primary installer does not work, there are two things you can try:</p>
 <p>Deploying on OpenWRT depends a lot on the version of OpenWRT and the hardware being used. If the primary installer does not work, there are two things you can try:</p>

+ 1 - 0
docs/_build/html/index.html

@@ -629,6 +629,7 @@
 <ul>
 <ul>
 <li class="toctree-l1"><a class="reference internal" href="support.html">Support</a><ul>
 <li class="toctree-l1"><a class="reference internal" href="support.html">Support</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="support.html#faq">FAQ</a></li>
 <li class="toctree-l2"><a class="reference internal" href="support.html#faq">FAQ</a></li>
+<li class="toctree-l2"><a class="reference internal" href="support.html#telemetry">Telemetry</a></li>
 <li class="toctree-l2"><a class="reference internal" href="support.html#contact">Contact</a></li>
 <li class="toctree-l2"><a class="reference internal" href="support.html#contact">Contact</a></li>
 </ul>
 </ul>
 </li>
 </li>

File diff suppressed because it is too large
+ 0 - 0
docs/_build/html/searchindex.js


+ 53 - 11
docs/_build/html/server-installation.html

@@ -292,6 +292,8 @@
         <li class="md-nav__item"><a href="#config-file-reference" class="md-nav__link">Config File Reference</a>
         <li class="md-nav__item"><a href="#config-file-reference" class="md-nav__link">Config File Reference</a>
         </li>
         </li>
         <li class="md-nav__item"><a href="#compose-file-annotated" class="md-nav__link">Compose File - Annotated</a>
         <li class="md-nav__item"><a href="#compose-file-annotated" class="md-nav__link">Compose File - Annotated</a>
+        </li>
+        <li class="md-nav__item"><a href="#available-docker-compose-files" class="md-nav__link">Available docker-compose files</a>
         </li></ul>
         </li></ul>
             </nav>
             </nav>
         </li>
         </li>
@@ -309,13 +311,15 @@
         </li>
         </li>
         <li class="md-nav__item"><a href="#linux-install-without-docker" class="md-nav__link">Linux Install without Docker</a><nav class="md-nav">
         <li class="md-nav__item"><a href="#linux-install-without-docker" class="md-nav__link">Linux Install without Docker</a><nav class="md-nav">
               <ul class="md-nav__list">
               <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#rqlite-setup" class="md-nav__link">rqlite Setup</a>
+        <li class="md-nav__item"><a href="#database-setup-optional" class="md-nav__link">Database Setup (optional)</a>
         </li>
         </li>
         <li class="md-nav__item"><a href="#server-setup" class="md-nav__link">Server Setup</a>
         <li class="md-nav__item"><a href="#server-setup" class="md-nav__link">Server Setup</a>
         </li>
         </li>
         <li class="md-nav__item"><a href="#ui-setup" class="md-nav__link">UI Setup</a>
         <li class="md-nav__item"><a href="#ui-setup" class="md-nav__link">UI Setup</a>
         </li>
         </li>
-        <li class="md-nav__item"><a href="#coredns-setup" class="md-nav__link">CoreDNS Setup</a>
+        <li class="md-nav__item"><a href="#coredns-setup-optional" class="md-nav__link">CoreDNS Setup (optional)</a>
+        </li>
+        <li class="md-nav__item"><a href="#proxy-load-balancer" class="md-nav__link">Proxy / Load Balancer</a>
         </li></ul>
         </li></ul>
             </nav>
             </nav>
         </li>
         </li>
@@ -351,7 +355,7 @@
               <ul class="md-nav__list">
               <ul class="md-nav__list">
         <li class="md-nav__item"><a href="#load-balancer-setup" class="md-nav__link">1. Load Balancer Setup</a>
         <li class="md-nav__item"><a href="#load-balancer-setup" class="md-nav__link">1. Load Balancer Setup</a>
         </li>
         </li>
-        <li class="md-nav__item"><a href="#id1" class="md-nav__link">2. RQLite Setup</a>
+        <li class="md-nav__item"><a href="#rqlite-setup" class="md-nav__link">2. RQLite Setup</a>
         </li>
         </li>
         <li class="md-nav__item"><a href="#netmaker-setup" class="md-nav__link">3. Netmaker Setup</a>
         <li class="md-nav__item"><a href="#netmaker-setup" class="md-nav__link">3. Netmaker Setup</a>
         </li>
         </li>
@@ -524,6 +528,8 @@
         <li class="md-nav__item"><a href="#config-file-reference" class="md-nav__link">Config File Reference</a>
         <li class="md-nav__item"><a href="#config-file-reference" class="md-nav__link">Config File Reference</a>
         </li>
         </li>
         <li class="md-nav__item"><a href="#compose-file-annotated" class="md-nav__link">Compose File - Annotated</a>
         <li class="md-nav__item"><a href="#compose-file-annotated" class="md-nav__link">Compose File - Annotated</a>
+        </li>
+        <li class="md-nav__item"><a href="#available-docker-compose-files" class="md-nav__link">Available docker-compose files</a>
         </li></ul>
         </li></ul>
             </nav>
             </nav>
         </li>
         </li>
@@ -541,13 +547,15 @@
         </li>
         </li>
         <li class="md-nav__item"><a href="#linux-install-without-docker" class="md-nav__link">Linux Install without Docker</a><nav class="md-nav">
         <li class="md-nav__item"><a href="#linux-install-without-docker" class="md-nav__link">Linux Install without Docker</a><nav class="md-nav">
               <ul class="md-nav__list">
               <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#rqlite-setup" class="md-nav__link">rqlite Setup</a>
+        <li class="md-nav__item"><a href="#database-setup-optional" class="md-nav__link">Database Setup (optional)</a>
         </li>
         </li>
         <li class="md-nav__item"><a href="#server-setup" class="md-nav__link">Server Setup</a>
         <li class="md-nav__item"><a href="#server-setup" class="md-nav__link">Server Setup</a>
         </li>
         </li>
         <li class="md-nav__item"><a href="#ui-setup" class="md-nav__link">UI Setup</a>
         <li class="md-nav__item"><a href="#ui-setup" class="md-nav__link">UI Setup</a>
         </li>
         </li>
-        <li class="md-nav__item"><a href="#coredns-setup" class="md-nav__link">CoreDNS Setup</a>
+        <li class="md-nav__item"><a href="#coredns-setup-optional" class="md-nav__link">CoreDNS Setup (optional)</a>
+        </li>
+        <li class="md-nav__item"><a href="#proxy-load-balancer" class="md-nav__link">Proxy / Load Balancer</a>
         </li></ul>
         </li></ul>
             </nav>
             </nav>
         </li>
         </li>
@@ -583,7 +591,7 @@
               <ul class="md-nav__list">
               <ul class="md-nav__list">
         <li class="md-nav__item"><a href="#load-balancer-setup" class="md-nav__link">1. Load Balancer Setup</a>
         <li class="md-nav__item"><a href="#load-balancer-setup" class="md-nav__link">1. Load Balancer Setup</a>
         </li>
         </li>
-        <li class="md-nav__item"><a href="#id1" class="md-nav__link">2. RQLite Setup</a>
+        <li class="md-nav__item"><a href="#rqlite-setup" class="md-nav__link">2. RQLite Setup</a>
         </li>
         </li>
         <li class="md-nav__item"><a href="#netmaker-setup" class="md-nav__link">3. Netmaker Setup</a>
         <li class="md-nav__item"><a href="#netmaker-setup" class="md-nav__link">3. Netmaker Setup</a>
         </li>
         </li>
@@ -692,6 +700,17 @@
 <dt>RCE:</dt><dd><p><strong>Default:</strong> “off”</p>
 <dt>RCE:</dt><dd><p><strong>Default:</strong> “off”</p>
 <p><strong>Description:</strong> The server enables you to set PostUp and PostDown commands for nodes, which is standard for WireGuard with wg-quick, but is also <strong>Remote Code Execution</strong>, which is a critical vulnerability if the server is exploited. Because of this, it’s turned off by default, but if turned on, PostUp and PostDown become editable.</p>
 <p><strong>Description:</strong> The server enables you to set PostUp and PostDown commands for nodes, which is standard for WireGuard with wg-quick, but is also <strong>Remote Code Execution</strong>, which is a critical vulnerability if the server is exploited. Because of this, it’s turned off by default, but if turned on, PostUp and PostDown become editable.</p>
 </dd>
 </dd>
+<dt>SERVER_GRPC_WIREGUARD</dt><dd><p><strong>Depreciated:</strong> no longer in use</p>
+</dd>
+<dt>DISPLAY_KEYS</dt><dd><p><strong>Default:</strong> “on”</p>
+<p><strong>Description:</strong> If “on”, will allow you to always show the key values of “access keys”. This could be considered a vulnerability, so if turned “off”, will only display key values once, and it is up to the users to store the key values locally.</p>
+</dd>
+<dt>NODE_ID</dt><dd><p><strong>Default:</strong> &lt;system mac addres&gt;</p>
+<p><strong>Description:</strong> This setting is used for HA configurations of the server, to identify between different servers. Nodes are given ID’s like netmaker-1, netmaker-2, and netmaker-3. If the server is not HA, there is no reason to set this field.</p>
+</dd>
+<dt>TELEMETRY</dt><dd><p><strong>Default:</strong> “on”</p>
+<p><strong>Description:</strong> If “on”, the server will send anonymous telemetry data once daily, which is used to improve the product. Data sent includes counts (integer values) for the number of nodes, types of nodes, users, and networks. It also sends the version of the server.</p>
+</dd>
 </dl>
 </dl>
 
 
 
 
@@ -758,6 +777,8 @@
       <span class="nt">SERVER_API_CONN_STRING</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># Changes the api connection string. IP:PORT format. By default is empty and uses SERVER_HOST:API_PORT</span>
       <span class="nt">SERVER_API_CONN_STRING</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># Changes the api connection string. IP:PORT format. By default is empty and uses SERVER_HOST:API_PORT</span>
       <span class="nt">SERVER_GRPC_CONN_STRING</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># Changes the grpc connection string. IP:PORT format. By default is empty and uses SERVER_HOST:GRPC_PORT</span>
       <span class="nt">SERVER_GRPC_CONN_STRING</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># Changes the grpc connection string. IP:PORT format. By default is empty and uses SERVER_HOST:GRPC_PORT</span>
       <span class="nt">RCE</span><span class="p">:</span> <span class="s">"off"</span> <span class="c1"># Enables setting PostUp and PostDown (arbitrary commands) on nodes from the server. Off by default.</span>
       <span class="nt">RCE</span><span class="p">:</span> <span class="s">"off"</span> <span class="c1"># Enables setting PostUp and PostDown (arbitrary commands) on nodes from the server. Off by default.</span>
+      <span class="nt">NODE_ID</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># Sets the name/id of the nodes that the server creates. Necessary for HA configurations to identify between servers (for instance, netmaker-1, netmaker-2, etc). For non-HA deployments, is not necessary.</span>
+      <span class="nt">TELEMETRY</span><span class="p">:</span> <span class="s">"on"</span> <span class="c1"># Whether or not to send telemetry data to help improve Netmaker. Switch to "off" to opt out of sending telemetry.</span>
   <span class="nt">netmaker-ui</span><span class="p">:</span> <span class="c1"># The Netmaker UI Component</span>
   <span class="nt">netmaker-ui</span><span class="p">:</span> <span class="c1"># The Netmaker UI Component</span>
     <span class="nt">container_name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">netmaker-ui</span>
     <span class="nt">container_name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">netmaker-ui</span>
     <span class="nt">depends_on</span><span class="p">:</span>
     <span class="nt">depends_on</span><span class="p">:</span>
@@ -787,6 +808,20 @@
 </div>
 </div>
 
 
 
 
+<h3 id="available-docker-compose-files">Available docker-compose files<a class="headerlink" href="#available-docker-compose-files" title="Permalink to this headline">¶</a></h3>
+<p>The default options for docker-compose can be found here: <a class="reference external" href="https://github.com/gravitl/netmaker/tree/master/compose">https://github.com/gravitl/netmaker/tree/master/compose</a></p>
+<p>The following is a brief description of each:</p>
+<ul class="simple">
+<li><p><a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.contained.yml">docker-compose.contained.yml</a> - This is the default docker-compose, used in the quick start and deployment script in the README on GitHub. It deploys Netmaker with all options included (Caddy and CoreDNS) and has “self-contained” netclients, meaning they do not affect host networking.</p></li>
+<li><p><a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.coredns.yml">docker-compose.coredns.yml</a> - This is a simple compose used to spin up a standalone CoreDNS server. Can be useful if, for instance, you are unning Netmaker on baremetal but need CoreDNS.</p></li>
+<li><p><a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.hostnetwork.yml">docker-compose.hostnetwork.yml</a> - This is similar to the docker-compose.contained.yml but with a key difference: it has advanced permissions and mounts host volumes to control networking on the host level.</p></li>
+<li><p><a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.nocaddy.yml">docker-compose.nocaddy.yml</a> -= This is the same as docker-compose.contained.yml but without Caddy, in case you need to use a different proxy like Nginx, Traefik, or HAProxy.</p></li>
+<li><p><a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.nodns.yml">docker-compose.nodns.yml</a> - This is the same as docker-compose.contained.yml but without CoreDNS, in which case you will not have the Private DNS feature.</p></li>
+<li><p><a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.reference.yml">docker-compose.reference.yml</a> - This is the same as docker-compose.contained.yml but with all variable options on display and annotated (it’s what we show right above this section). Use this to determine which variables you should add or change in your configuration.</p></li>
+<li><p><a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.yml">docker-compose.yml</a> - This is a renamed docker-compose.contained.yml. It is meant only to act as a placeholder for what we consider the “primary” docker-compose that users should work with.</p></li>
+</ul>
+
+
 
 
 <h2 id="dns-mode-setup">DNS Mode Setup<a class="headerlink" href="#dns-mode-setup" title="Permalink to this headline">¶</a></h2>
 <h2 id="dns-mode-setup">DNS Mode Setup<a class="headerlink" href="#dns-mode-setup" title="Permalink to this headline">¶</a></h2>
 <p>If you plan on running the server in DNS Mode, know that a <a class="reference external" href="https://coredns.io/manual/toc/">CoreDNS Server</a> will be installed. CoreDNS is a light-weight, fast, and easy-to-configure DNS server. It is recommended to bind CoreDNS to port 53 of the host system, and it will do so by default. The clients will expect the nameserver to be on port 53, and many systems have issues resolving a different port.</p>
 <p>If you plan on running the server in DNS Mode, know that a <a class="reference external" href="https://coredns.io/manual/toc/">CoreDNS Server</a> will be installed. CoreDNS is a light-weight, fast, and easy-to-configure DNS server. It is recommended to bind CoreDNS to port 53 of the host system, and it will do so by default. The clients will expect the nameserver to be on port 53, and many systems have issues resolving a different port.</p>
@@ -842,15 +877,16 @@ docker-compose up -d`
 
 
 
 
 <span id="nodocker"></span><h2 id="linux-install-without-docker">Linux Install without Docker<a class="headerlink" href="#linux-install-without-docker" title="Permalink to this headline">¶</a></h2>
 <span id="nodocker"></span><h2 id="linux-install-without-docker">Linux Install without Docker<a class="headerlink" href="#linux-install-without-docker" title="Permalink to this headline">¶</a></h2>
-<p>Most systems support Docker, but some do not. In such environments, there are many options for installing Netmaker. Netmaker is available as a binary file, and there is a zip file of the Netmaker UI static HTML on GitHub. Beyond the UI and Server, you need to install MongoDB and CoreDNS (optional).</p>
-<p>To start, we recommend following the Nginx instructions in the <a class="reference internal" href="quick-start.html"><span class="doc">Quick Install</span></a> guide to enable SSL for your environment.</p>
+<p>Most systems support Docker, but some do not. In such environments, there are many options for installing Netmaker. Netmaker is available as a binary file, and there is a zip file of the Netmaker UI static HTML on GitHub. Beyond the UI and Server, you may want to optionally install a database (sqlite is embedded, rqlite or postgres are supported) and CoreDNS (also optional).</p>
 <p>Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.</p>
 <p>Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.</p>
 
 
-<h3 id="rqlite-setup">rqlite Setup<a class="headerlink" href="#rqlite-setup" title="Permalink to this headline">¶</a></h3>
+<h3 id="database-setup-optional">Database Setup (optional)<a class="headerlink" href="#database-setup-optional" title="Permalink to this headline">¶</a></h3>
+<p>You can run the netmaker binary standalone and it will run an embedded sqlite server. Data goes in the data/ directory. Optionally, you can run PostgreSQL or rqlite. Instructions for rqlite are below.</p>
 <ol class="arabic simple">
 <ol class="arabic simple">
 <li><p>Install rqlite on your server: <a class="reference external" href="https://github.com/rqlite/rqlite">https://github.com/rqlite/rqlite</a></p></li>
 <li><p>Install rqlite on your server: <a class="reference external" href="https://github.com/rqlite/rqlite">https://github.com/rqlite/rqlite</a></p></li>
 <li><p>Run rqlite: rqlited -node-id 1 ~/node.1</p></li>
 <li><p>Run rqlite: rqlited -node-id 1 ~/node.1</p></li>
 </ol>
 </ol>
+<p>If using rqlite or postgres, you must change the DATABASE environment/config variable and enter connection details.</p>
 
 
 
 
 <h3 id="server-setup">Server Setup<a class="headerlink" href="#server-setup" title="Permalink to this headline">¶</a></h3>
 <h3 id="server-setup">Server Setup<a class="headerlink" href="#server-setup" title="Permalink to this headline">¶</a></h3>
@@ -883,7 +919,13 @@ docker-compose up -d`
 </div>
 </div>
 
 
 
 
-<h3 id="coredns-setup">CoreDNS Setup<a class="headerlink" href="#coredns-setup" title="Permalink to this headline">¶</a></h3>
+<h3 id="coredns-setup-optional">CoreDNS Setup (optional)<a class="headerlink" href="#coredns-setup-optional" title="Permalink to this headline">¶</a></h3>
+<p>CoreDNS is only required if you want private DNS features. Once installed, you must set the CoreDNS variables in the env settings of the server.</p>
+<p>See <a class="reference external" href="https://coredns.io/manual/toc/#installation">https://coredns.io/manual/toc/#installation</a></p>
+
+
+<h3 id="proxy-load-balancer">Proxy / Load Balancer<a class="headerlink" href="#proxy-load-balancer" title="Permalink to this headline">¶</a></h3>
+<p>You will need to proxy connections to your UI and Server. By default the ports are 8081, 8082, and 50051 (grpc). This proxy should handle SSL certificates. We recommend Caddy or Nginx (you can follow the Nginx guide in these docs). The proxy must be able to handle gRPC connections.</p>
 
 
 
 
 
 
@@ -1091,7 +1133,7 @@ This install has some notable exceptions:
 <p>Your load balancer of choice will send requests to the Netmaker servers. Setup is similar to the various guides we have created for Nginx, Caddy, and Traefik. SSL certificates must also be configured and handled by the LB.</p>
 <p>Your load balancer of choice will send requests to the Netmaker servers. Setup is similar to the various guides we have created for Nginx, Caddy, and Traefik. SSL certificates must also be configured and handled by the LB.</p>
 
 
 
 
-<h3 id="id1">2. RQLite Setup<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h3>
+<h3 id="rqlite-setup">2. RQLite Setup<a class="headerlink" href="#rqlite-setup" title="Permalink to this headline">¶</a></h3>
 <p>RQLite is the included distributed datastore for an HA Netmaker installation. If you have a different corporate database you wish to integrate, Netmaker is easily extended to other DB’s. If this is a requirement, please contact us.</p>
 <p>RQLite is the included distributed datastore for an HA Netmaker installation. If you have a different corporate database you wish to integrate, Netmaker is easily extended to other DB’s. If this is a requirement, please contact us.</p>
 <p>Assuming you use Rqlite, you must run it on each Netmaker server VM, or alongside that VM as a container. Setup a config.json for database credentials (password supports BCRYPT HASHING) and mount in working directory of rqlite and specify with <cite>-auth config.json</cite> :</p>
 <p>Assuming you use Rqlite, you must run it on each Netmaker server VM, or alongside that VM as a container. Setup a config.json for database credentials (password supports BCRYPT HASHING) and mount in working directory of rqlite and specify with <cite>-auth config.json</cite> :</p>
 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[{</span>
 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[{</span>

+ 34 - 0
docs/_build/html/support.html

@@ -351,6 +351,8 @@
         </li></ul>
         </li></ul>
             </nav>
             </nav>
         </li>
         </li>
+        <li class="md-nav__item"><a href="#telemetry" class="md-nav__link">Telemetry</a>
+        </li>
         <li class="md-nav__item"><a href="#contact" class="md-nav__link">Contact</a>
         <li class="md-nav__item"><a href="#contact" class="md-nav__link">Contact</a>
         </li></ul>
         </li></ul>
             </nav>
             </nav>
@@ -364,6 +366,13 @@
       <a href="#faq" class="md-nav__link">FAQ</a>
       <a href="#faq" class="md-nav__link">FAQ</a>
       
       
     
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#telemetry" class="md-nav__link">Telemetry</a>
+      
+    
     </li>
     </li>
     <li class="md-nav__item">
     <li class="md-nav__item">
     
     
@@ -416,6 +425,8 @@
         </li></ul>
         </li></ul>
             </nav>
             </nav>
         </li>
         </li>
+        <li class="md-nav__item"><a href="#telemetry" class="md-nav__link">Telemetry</a>
+        </li>
         <li class="md-nav__item"><a href="#contact" class="md-nav__link">Contact</a>
         <li class="md-nav__item"><a href="#contact" class="md-nav__link">Contact</a>
         </li></ul>
         </li></ul>
             </nav>
             </nav>
@@ -459,6 +470,29 @@
 
 
 
 
 
 
+<h2 id="telemetry">Telemetry<a class="headerlink" href="#telemetry" title="Permalink to this headline">¶</a></h2>
+<p>As of v0.10.0, Netmaker collects “opt-out” telemetry data. To opt out, simply set “TELEMETRY=off” in your docker-compose file.</p>
+<p>Please consider participating in telemetry, as it helps us focus on the features and bug fixes which are most useful to users. Netmaker is a broad platform, and without this data, it is difficult to know where the team should spend its limited resources.</p>
+<p>The following is the full list of telemetry data we collect. Besides “Server Version” all data is simply an integer count:</p>
+<ul class="simple">
+<li><p>Randomized server ID</p></li>
+<li><p>Count of nodes</p></li>
+<li><p>Count of “non-server” nodes</p></li>
+<li><p>Count of external clients</p></li>
+<li><p>Count of networks</p></li>
+<li><p>Count of users</p></li>
+<li><p>Count of linux nodes</p></li>
+<li><p>Count of freebsd nodes</p></li>
+<li><p>Count of macos nodes</p></li>
+<li><p>Count of windows nodes</p></li>
+<li><p>Count of docker nodes</p></li>
+<li><p>Count of k8s nodes</p></li>
+<li><p>Server version</p></li>
+</ul>
+<p>We use  <a class="reference external" href="https://https://posthog.com/">PostHog</a>, an open source and trusted framework for telemetry data.</p>
+<p>To look at exactly we collect telemetry, you can view the source code under serverctl/telemetry.go: <a class="reference external" href="https://github.com/gravitl/netmaker/blob/master/serverctl/telemetry.go">https://github.com/gravitl/netmaker/blob/master/serverctl/telemetry.go</a></p>
+
+
 <h2 id="contact">Contact<a class="headerlink" href="#contact" title="Permalink to this headline">¶</a></h2>
 <h2 id="contact">Contact<a class="headerlink" href="#contact" title="Permalink to this headline">¶</a></h2>
 <p>If you need help, try the discord or open a GitHub ticket.</p>
 <p>If you need help, try the discord or open a GitHub ticket.</p>
 <p>Email: <a class="reference external" href="mailto:info%40gravitl.com">info<span>@</span>gravitl<span>.</span>com</a></p>
 <p>Email: <a class="reference external" href="mailto:info%40gravitl.com">info<span>@</span>gravitl<span>.</span>com</a></p>

+ 5 - 1
docs/_build/html/troubleshoot.html

@@ -467,7 +467,11 @@ You can also sign-up for updates at our <a class="reference external" href="http
 
 
 
 
 <h2 id="server">Server<a class="headerlink" href="#server" title="Permalink to this headline">¶</a></h2>
 <h2 id="server">Server<a class="headerlink" href="#server" title="Permalink to this headline">¶</a></h2>
-<dl class="simple">
+<dl>
+<dt><strong>How do I use a private address from the Netmaker Server? How do I contact nodes using their private addresses from the server?</strong></dt><dd><p>Default nodes appear in each network with the “netmaker” name. These nodes are created by, and attached to, the server. The server is contained in docker, meaning these clients are also contained in docker. Their networking stack is also contained in docker. The “netmaker” nodes are meant to function as network utilities. They assist with UDP Hole Punching and can run Relays, Egress, and Ingress. However, they are meant to stay contained in the server. They do not touch the host networking stack.</p>
+<p>If you want to give the physical server / VM a private IP in the netmaker network, you must deploy an <strong>additional</strong> node using the standard netclient. The only note here is that the server consumes ports 51821-51831, so you will need to give it a port outside this range, e.x. <cite>./netclient join &lt;token&gt; –port 51835</cite>.</p>
+<p>One a netclient is deployed to the underlying server/VM, you will be able to use the private address to reach other nodes from the host, or to reach the server over the private network.</p>
+</dd>
 <dt><strong>I upgraded from 0.7 to 0.8 and now I dont have any data in my server!</strong></dt><dd><p>In 0.8, sqlite becomes the default database. If you were running with rqlite, you must set the DATABASE environment variable to rqlite in order to continue using rqlite.</p>
 <dt><strong>I upgraded from 0.7 to 0.8 and now I dont have any data in my server!</strong></dt><dd><p>In 0.8, sqlite becomes the default database. If you were running with rqlite, you must set the DATABASE environment variable to rqlite in order to continue using rqlite.</p>
 </dd>
 </dd>
 <dt><strong>Can I secure/encrypt all the traffic to my server and UI?</strong></dt><dd><p>This can fairly simple to achieve assuming you have access to a domain and are familiar with Nginx.
 <dt><strong>Can I secure/encrypt all the traffic to my server and UI?</strong></dt><dd><p>This can fairly simple to achieve assuming you have access to a domain and are familiar with Nginx.

+ 59 - 47
docs/api.rst

@@ -17,8 +17,11 @@ API calls must be authenticated via a header of  the format  `-H "Authorization:
 
 
 Format of Calls for Curl
 Format of Calls for Curl
 ========================
 ========================
-Requests take the format of `curl -H "Authorization: Bearer <YOUR_SECRET_KEY>" -H 'Content-Type: application/json' localhost:8081/api/path/to/endpoint`
+Requests take the format of 
 
 
+.. code-block::
+
+    curl -H "Authorization: Bearer <YOUR_SECRET_KEY>" -H 'Content-Type: application/json' localhost:8081/api/path/to/endpoint
 
 
 API Documentation
 API Documentation
 =================
 =================
@@ -41,18 +44,21 @@ Networks API
   
   
 Networks API Call Examples
 Networks API Call Examples
 --------------------------  
 --------------------------  
-  
-**Get All Networks:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks | jq`
 
 
-**Create Network:** `curl -d '{"addressrange":"10.70.0.0/16","netid":"skynet"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks`
+.. code-block::
+
+    Get All Networks: curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks | jq
 
 
-**Get Network:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet | jq`
+    Create Network: curl -d '{"addressrange":"10.70.0.0/16","netid":"skynet"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks
 
 
-**Update Network:** `curl -X PUT -d '{"displayname":"my-house"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet`
+    Get Network: curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet | jq
 
 
-**Delete Network:** `curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet`
+    Update Network: curl -X PUT -d '{"displayname":"my-house"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet
+
+    Delete Network: curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet
+
+    Cycle PublicKeys on all Nodes: curl -X POST -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keyupdate
 
 
-**Cycle PublicKeys on all Nodes:** `curl -X POST -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keyupdate`
 
 
 Access Keys API
 Access Keys API
 ---------------
 ---------------
@@ -66,13 +72,15 @@ Access Keys API
   
   
 Access Keys API Call Examples
 Access Keys API Call Examples
 -----------------------------
 -----------------------------
-   
-**Get All Keys:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys | jq`
-  
-**Create Key:** `curl -d '{"uses":10,"name":"mykey"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet/keys`
-  
-**Delete Key:** `curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys/mykey`
-  
+
+.. code-block::
+
+    Get All Keys: curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys | jq
+    
+    Create Key: curl -d '{"uses":10,"name":"mykey"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet/keys
+    
+    Delete Key: curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys/mykey
+
     
     
 Nodes API
 Nodes API
 ---------
 ---------
@@ -104,29 +112,31 @@ Nodes API
   
   
 Nodes API Call Examples
 Nodes API Call Examples
 ----------------------- 
 ----------------------- 
-  
-**Get All Nodes:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes | jq`
-  
-**Get Network Nodes:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet | jq`
+
+.. code-block::
+
+    Get All Nodes: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes | jq
     
     
-**Create Node:** `curl  -d  '{ "endpoint": 100.200.100.200, "publickey": aorijqalrik3ajflaqrdajhkr,"macaddress": "8c:90:b5:06:f1:d9","password": "reallysecret","localaddress": "172.16.16.1","accesskey": "aA3bVG0rnItIRXDx","listenport": 6400}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet`
+    Get Network Nodes: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet | jq
+        
+    Create Node: curl  -d  '{ "endpoint": 100.200.100.200, "publickey": aorijqalrik3ajflaqrdajhkr,"macaddress": "8c:90:b5:06:f1:d9","password": "reallysecret","localaddress": "172.16.16.1","accesskey": "aA3bVG0rnItIRXDx","listenport": 6400}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet
+        
+    Get Node: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet/{macaddress} | jq  
     
     
-**Get Node:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet/{macaddress} | jq`  
-  
-**Update Node:** `curl -X PUT -d '{"name":"laptop1"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9`
-  
-**Delete Node:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/skynet/nodes/8c:90:b5:06:f1:d9`
-  
-**Create a Gateway:** `curl  -d  '{ "rangestring": "172.31.0.0/16", "interface": "eth0"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/creategateway`
-  
-**Delete a Gateway:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/deletegateway`
-  
-**Approve a Pending Node:** `curl -X POST -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/approve`
-  
-**Get Last Modified Date (Last Modified Node in Network):** `curl -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/adm/skynet/lastmodified`
+    Update Node: curl -X PUT -d '{"name":"laptop1"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9
+    
+    Delete Node: curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/skynet/nodes/8c:90:b5:06:f1:d9
+    
+    Create a Gateway: curl  -d  '{ "rangestring": "172.31.0.0/16", "interface": "eth0"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/creategateway
+    
+    Delete a Gateway: curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/deletegateway
+    
+    Approve a Pending Node: curl -X POST -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/approve
+    
+    Get Last Modified Date (Last Modified Node in Network): curl -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/adm/skynet/lastmodified
+
+    Authenticate: curl -d  '{"macaddress": "8c:90:b5:06:f1:d9", "password": "YOUR_PASSWORD"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate
 
 
-**Authenticate:** `curl -d  '{"macaddress": "8c:90:b5:06:f1:d9", "password": "YOUR_PASSWORD"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate`
-  
 
 
 Users API
 Users API
 -----------------------
 -----------------------
@@ -148,19 +158,21 @@ Users API
   
   
 Users API Calls Examples
 Users API Calls Examples
 ------------------------
 ------------------------
-  
-**Get User:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/{username} | jq`
 
 
-**Update User:** `curl -X PUT -d '{"password":"noonewillguessthis"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}`
-  
-**Delete User:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}`
-  
-**Check for Admin User:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/adm/hasadmin`
-  
-**Create Admin User:** `curl -d '{ "username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/adm/createadmin`
-   
-**Authenticate:** `curl -d  '{"username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate`
-  
+.. code-block::
+
+    Get User: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/{username} | jq
+
+    Update User: curl -X PUT -d '{"password":"noonewillguessthis"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}
+    
+    Delete User: curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}
+    
+    Check for Admin User: curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/adm/hasadmin
+    
+    Create Admin User: curl -d '{ "username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/adm/createadmin
+    
+    Authenticate: curl -d  '{"username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate
+
 
 
 Server Management API
 Server Management API
 ---------------------
 ---------------------

+ 11 - 1
docs/architecture.rst

@@ -47,7 +47,7 @@ Netmaker
 
 
 Netmaker is a platform built off of WireGuard which enables users to create mesh networks between their devices. Netmaker can create both full and partial mesh networks depending on the use case.
 Netmaker is a platform built off of WireGuard which enables users to create mesh networks between their devices. Netmaker can create both full and partial mesh networks depending on the use case.
 
 
-When we refer to Netmaker in aggregate, we are typically referring to Netmaker and the netclient, as well as other supporting services such as CoreDNS, rqlite, and UI webserver.
+When we refer to Netmaker in aggregate, we are typically referring to Netmaker and the netclient, as well as other supporting services such as CoreDNS, rqlite, and UI webserver. There is also almost always a proxy server / LB, which is typically Caddy.
 
 
 From an end user perspective, they typically interact with the Netmaker UI, or even just run the install script for the netclient on their devices. The other components run in the background invisibly. 
 From an end user perspective, they typically interact with the Netmaker UI, or even just run the install script for the netclient on their devices. The other components run in the background invisibly. 
 
 
@@ -85,6 +85,7 @@ These modes include client mode and dns mode. Either of these can be disabled bu
 
 
 The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.
 The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.
 
 
+The components of the server are usually proxied via Caddy, or an alternative like Nginx and Traefik. The proxy handles SSL certificates to secure traffic, and routes to the UI, API, and gRPC server.
 
 
 Netclient
 Netclient
 ----------------
 ----------------
@@ -124,6 +125,15 @@ CoreDNS
 
 
 Netmaker allows users to provide and manage Private DNS for their nodes. This requires a nameserver, and CoreDNS is the chosen nameserver. CoreDNS is lightweight and extensible. CoreDNS loads dns settings from a simple file, managed by Netmaker, and serves out DNS info for managed nodes. DNS can be tricky, and DNS management is currently only supported on a small set of devices, specifically those running systemd-resolved. However, the Netmaker CoreDNS instance can be added manually as a nameserver to other devices. DNS mode can also be turned off.
 Netmaker allows users to provide and manage Private DNS for their nodes. This requires a nameserver, and CoreDNS is the chosen nameserver. CoreDNS is lightweight and extensible. CoreDNS loads dns settings from a simple file, managed by Netmaker, and serves out DNS info for managed nodes. DNS can be tricky, and DNS management is currently only supported on a small set of devices, specifically those running systemd-resolved. However, the Netmaker CoreDNS instance can be added manually as a nameserver to other devices. DNS mode can also be turned off.
 
 
+Caddy
+-------
+
+Caddy is the default proxy for Netmaker if you set it up via Quick Start. Caddy is an extremely simple and docker-friendly proxy, which can be compared to Nginx, Traefik, or HAProxy. We use Caddy by default because of the ease of management, and integration with gRPC. A typical setup for Nginx might take dozens of lines of code, and we need to request and manage SSL certificates separately.
+
+Caddy handles all these things automatically in very few lines of code. You can see our default "Caddyfile" here, which is fed to the container and has all the configuration necessary to configure the proxy for our app:
+
+https://github.com/gravitl/netmaker/blob/master/docker/Caddyfile
+
 External Client
 External Client
 ----------------
 ----------------
 
 

+ 23 - 0
docs/client-installation.rst

@@ -30,6 +30,29 @@ Windows will by default have firewall rules that prevent inbound connections. If
 
 
 If you want to allow all peers access, but do not want to configure firewall rules for all peers, you can configure access for one peer, and set it as a Relay Server.
 If you want to allow all peers access, but do not want to configure firewall rules for all peers, you can configure access for one peer, and set it as a Relay Server.
 
 
+Running the install script
+----------------------------
+
+Some file locations have issues running the install script, such as running from the root C:/ folder. Users have noted the following locations work well for running the install powershell script:
+
+- `C:/Program Files/wireguard`
+- `C:/Windows/System32`
+
+Running netclient commands
+----------------------------
+
+If running the netclient manually ("netclient join", "netclient checkin", "netclient pull") it should be run from outside of the installed directory, which will be either:
+
+- `C:/Program Files/netclient`
+- `C:/ProgramData/netclient`
+
+It is better to call it from a different directory.
+
+High CPU Utilization
+--------------------------
+
+With some versions of WireGuard on Windows, high CPU utilization has been found with the netclient. This is typically due to interaction with the WireGuard GUI component (app). If you're experiencing high CPU utilization, close the WireGuard app. WireGuard will still be running, but the CPU usage should go back down to normal.
+
 Notes on OpenWRT
 Notes on OpenWRT
 ===========================
 ===========================
 
 

+ 52 - 8
docs/server-installation.rst

@@ -143,9 +143,26 @@ RCE:
 
 
     **Description:** The server enables you to set PostUp and PostDown commands for nodes, which is standard for WireGuard with wg-quick, but is also **Remote Code Execution**, which is a critical vulnerability if the server is exploited. Because of this, it's turned off by default, but if turned on, PostUp and PostDown become editable.
     **Description:** The server enables you to set PostUp and PostDown commands for nodes, which is standard for WireGuard with wg-quick, but is also **Remote Code Execution**, which is a critical vulnerability if the server is exploited. Because of this, it's turned off by default, but if turned on, PostUp and PostDown become editable.
 
 
+SERVER_GRPC_WIREGUARD
+    **Depreciated:** no longer in use
+
+DISPLAY_KEYS
+    **Default:** "on"
+
+    **Description:** If "on", will allow you to always show the key values of "access keys". This could be considered a vulnerability, so if turned "off", will only display key values once, and it is up to the users to store the key values locally.
+
+NODE_ID
+    **Default:** <system mac addres>
+
+    **Description:** This setting is used for HA configurations of the server, to identify between different servers. Nodes are given ID's like netmaker-1, netmaker-2, and netmaker-3. If the server is not HA, there is no reason to set this field.
+
+TELEMETRY
+    **Default:** "on"
+
+    **Description:** If "on", the server will send anonymous telemetry data once daily, which is used to improve the product. Data sent includes counts (integer values) for the number of nodes, types of nodes, users, and networks. It also sends the version of the server.
 
 
 Config File Reference
 Config File Reference
-----------------------
+-----------------------
 A config file may be placed under config/environments/<env-name>.yml. To read this file at runtime, provide the environment variable NETMAKER_ENV at runtime. For instance, dev.yml paired with ENV=dev. Netmaker will load the specified Config file. This allows you to store and manage configurations for different environments. Below is a reference Config File you may use.
 A config file may be placed under config/environments/<env-name>.yml. To read this file at runtime, provide the environment variable NETMAKER_ENV at runtime. For instance, dev.yml paired with ENV=dev. Netmaker will load the specified Config file. This allows you to store and manage configurations for different environments. Below is a reference Config File you may use.
 
 
 .. literalinclude:: ../config/environments/dev.yaml
 .. literalinclude:: ../config/environments/dev.yaml
@@ -159,6 +176,20 @@ All environment variables and options are enabled in this file. It is the equiva
 .. literalinclude:: ../compose/docker-compose.reference.yml
 .. literalinclude:: ../compose/docker-compose.reference.yml
   :language: YAML
   :language: YAML
 
 
+Available docker-compose files
+---------------------------------
+
+The default options for docker-compose can be found here: https://github.com/gravitl/netmaker/tree/master/compose
+
+The following is a brief description of each:
+
+- `docker-compose.contained.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.contained.yml>`_ - This is the default docker-compose, used in the quick start and deployment script in the README on GitHub. It deploys Netmaker with all options included (Caddy and CoreDNS) and has "self-contained" netclients, meaning they do not affect host networking.
+- `docker-compose.coredns.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.coredns.yml>`_ - This is a simple compose used to spin up a standalone CoreDNS server. Can be useful if, for instance, you are unning Netmaker on baremetal but need CoreDNS.
+- `docker-compose.hostnetwork.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.hostnetwork.yml>`_ - This is similar to the docker-compose.contained.yml but with a key difference: it has advanced permissions and mounts host volumes to control networking on the host level.
+- `docker-compose.nocaddy.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.nocaddy.yml>`_ -= This is the same as docker-compose.contained.yml but without Caddy, in case you need to use a different proxy like Nginx, Traefik, or HAProxy.
+- `docker-compose.nodns.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.nodns.yml>`_ - This is the same as docker-compose.contained.yml but without CoreDNS, in which case you will not have the Private DNS feature.
+- `docker-compose.reference.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.reference.yml>`_ - This is the same as docker-compose.contained.yml but with all variable options on display and annotated (it's what we show right above this section). Use this to determine which variables you should add or change in your configuration.
+- `docker-compose.yml <https://github.com/gravitl/netmaker/blob/master/compose/docker-compose.yml>`_ - This is a renamed docker-compose.contained.yml. It is meant only to act as a placeholder for what we consider the "primary" docker-compose that users should work with.
 
 
 DNS Mode Setup
 DNS Mode Setup
 ====================================
 ====================================
@@ -230,18 +261,21 @@ This template is equivalent but omits CoreDNS.
 Linux Install without Docker
 Linux Install without Docker
 =============================
 =============================
 
 
-Most systems support Docker, but some do not. In such environments, there are many options for installing Netmaker. Netmaker is available as a binary file, and there is a zip file of the Netmaker UI static HTML on GitHub. Beyond the UI and Server, you need to install MongoDB and CoreDNS (optional). 
-
-To start, we recommend following the Nginx instructions in the :doc:`Quick Install <./quick-start>` guide to enable SSL for your environment.
+Most systems support Docker, but some do not. In such environments, there are many options for installing Netmaker. Netmaker is available as a binary file, and there is a zip file of the Netmaker UI static HTML on GitHub. Beyond the UI and Server, you may want to optionally install a database (sqlite is embedded, rqlite or postgres are supported) and CoreDNS (also optional). 
 
 
 Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.
 Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.
 
 
-rqlite Setup
-----------------
+Database Setup (optional)
+--------------------------
+
+You can run the netmaker binary standalone and it will run an embedded sqlite server. Data goes in the data/ directory. Optionally, you can run PostgreSQL or rqlite. Instructions for rqlite are below.
+
 1. Install rqlite on your server: https://github.com/rqlite/rqlite
 1. Install rqlite on your server: https://github.com/rqlite/rqlite
 
 
 2. Run rqlite: rqlited -node-id 1 ~/node.1
 2. Run rqlite: rqlited -node-id 1 ~/node.1
 
 
+If using rqlite or postgres, you must change the DATABASE environment/config variable and enter connection details.
+
 Server Setup
 Server Setup
 -------------
 -------------
 1. **Run the install script:** 
 1. **Run the install script:** 
@@ -271,8 +305,18 @@ The following uses Nginx as an http server. You may alternatively use Apache or
   sudo sh -c 'BACKEND_URL=http://<YOUR BACKEND API URL>:PORT /usr/share/nginx/html/generate_config_js.sh >/usr/share/nginx/html/config.js'
   sudo sh -c 'BACKEND_URL=http://<YOUR BACKEND API URL>:PORT /usr/share/nginx/html/generate_config_js.sh >/usr/share/nginx/html/config.js'
   sudo systemctl start nginx
   sudo systemctl start nginx
 
 
-CoreDNS Setup
-----------------
+CoreDNS Setup (optional)
+----------------------------
+
+CoreDNS is only required if you want private DNS features. Once installed, you must set the CoreDNS variables in the env settings of the server.
+
+See https://coredns.io/manual/toc/#installation
+
+Proxy / Load Balancer
+------------------------
+
+You will need to proxy connections to your UI and Server. By default the ports are 8081, 8082, and 50051 (grpc). This proxy should handle SSL certificates. We recommend Caddy or Nginx (you can follow the Nginx guide in these docs). The proxy must be able to handle gRPC connections.
+
 
 
 .. _KubeInstall:
 .. _KubeInstall:
 
 

+ 27 - 0
docs/support.rst

@@ -39,6 +39,33 @@ We believe the SSPL lets most people run the project the way they want, for both
 
 
 If you believe the SSPL will negatively impact your ability to use the project, please do not hesitate to reach out.
 If you believe the SSPL will negatively impact your ability to use the project, please do not hesitate to reach out.
 
 
+Telemetry
+==============
+
+As of v0.10.0, Netmaker collects "opt-out" telemetry data. To opt out, simply set "TELEMETRY=off" in your docker-compose file.
+
+Please consider participating in telemetry, as it helps us focus on the features and bug fixes which are most useful to users. Netmaker is a broad platform, and without this data, it is difficult to know where the team should spend its limited resources.
+
+The following is the full list of telemetry data we collect. Besides "Server Version" all data is simply an integer count:
+
+- Randomized server ID
+- Count of nodes
+- Count of "non-server" nodes
+- Count of external clients
+- Count of networks
+- Count of users
+- Count of linux nodes
+- Count of freebsd nodes
+- Count of macos nodes
+- Count of windows nodes
+- Count of docker nodes
+- Count of k8s nodes
+- Server version
+
+We use  `PostHog <https://https://posthog.com/>`_, an open source and trusted framework for telemetry data.
+
+To look at exactly we collect telemetry, you can view the source code under serverctl/telemetry.go: https://github.com/gravitl/netmaker/blob/master/serverctl/telemetry.go
+
 Contact
 Contact
 ===========
 ===========
 If you need help, try the discord or open a GitHub ticket.
 If you need help, try the discord or open a GitHub ticket.

+ 7 - 0
docs/troubleshoot.rst

@@ -29,6 +29,13 @@ Common Issues
 Server
 Server
 -------
 -------
 
 
+**How do I use a private address from the Netmaker Server? How do I contact nodes using their private addresses from the server?**
+  Default nodes appear in each network with the "netmaker" name. These nodes are created by, and attached to, the server. The server is contained in docker, meaning these clients are also contained in docker. Their networking stack is also contained in docker. The "netmaker" nodes are meant to function as network utilities. They assist with UDP Hole Punching and can run Relays, Egress, and Ingress. However, they are meant to stay contained in the server. They do not touch the host networking stack.
+
+  If you want to give the physical server / VM a private IP in the netmaker network, you must deploy an **additional** node using the standard netclient. The only note here is that the server consumes ports 51821-51831, so you will need to give it a port outside this range, e.x. `./netclient join <token> --port 51835`.
+
+  One a netclient is deployed to the underlying server/VM, you will be able to use the private address to reach other nodes from the host, or to reach the server over the private network.
+
 **I upgraded from 0.7 to 0.8 and now I dont have any data in my server!**
 **I upgraded from 0.7 to 0.8 and now I dont have any data in my server!**
   In 0.8, sqlite becomes the default database. If you were running with rqlite, you must set the DATABASE environment variable to rqlite in order to continue using rqlite.
   In 0.8, sqlite becomes the default database. If you were running with rqlite, you must set the DATABASE environment variable to rqlite in order to continue using rqlite.
 
 

+ 2 - 0
go.mod

@@ -45,7 +45,9 @@ require (
 	github.com/mdlayher/genetlink v1.0.0 // indirect
 	github.com/mdlayher/genetlink v1.0.0 // indirect
 	github.com/mdlayher/netlink v1.4.0 // indirect
 	github.com/mdlayher/netlink v1.4.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0 // indirect
 	github.com/russross/blackfriday/v2 v2.0.1 // indirect
 	github.com/russross/blackfriday/v2 v2.0.1 // indirect
 	github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
 	github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
+	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
 	google.golang.org/appengine v1.4.0 // indirect
 	google.golang.org/appengine v1.4.0 // indirect
 )
 )

+ 5 - 0
go.sum

@@ -130,6 +130,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0 h1:Y2hUrkfuM0on62KZOci/VLijlkdF/yeWU262BQgvcjE=
+github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0/go.mod h1:oa2sAs9tGai3VldabTV0eWejt/O4/OOD7azP8GaikqU=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
@@ -160,9 +162,12 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/txn2/txeh v1.3.0 h1:vnbv63htVMZCaQgLqVBxKvj2+HHHFUzNW7I183zjg3E=
 github.com/txn2/txeh v1.3.0 h1:vnbv63htVMZCaQgLqVBxKvj2+HHHFUzNW7I183zjg3E=
 github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw8=
 github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw8=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
 github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
+github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

+ 2 - 0
logic/nodes.go

@@ -412,6 +412,8 @@ func SetNodeDefaults(node *models.Node) {
 	node.SetDefaultMTU()
 	node.SetDefaultMTU()
 	node.SetDefaultIsRelayed()
 	node.SetDefaultIsRelayed()
 	node.SetDefaultIsRelay()
 	node.SetDefaultIsRelay()
+	node.SetDefaultIsDocker()
+	node.SetDefaultIsK8S()
 	node.KeyUpdateTimeStamp = time.Now().Unix()
 	node.KeyUpdateTimeStamp = time.Now().Unix()
 }
 }
 
 

+ 4 - 0
main.go

@@ -45,6 +45,10 @@ func initialize() { // Client Mode Prereq Check
 	}
 	}
 	logger.Log(0, "database successfully connected")
 	logger.Log(0, "database successfully connected")
 
 
+	err = serverctl.TelemetryCheckpoint()
+	if err != nil {
+		logger.Log(1, "Failed to send telemetry: ", err.Error())
+	}
 	var authProvider = auth.InitializeAuthProvider()
 	var authProvider = auth.InitializeAuthProvider()
 	if authProvider != "" {
 	if authProvider != "" {
 		logger.Log(0, "OAuth provider,", authProvider+",", "initialized")
 		logger.Log(0, "OAuth provider,", authProvider+",", "initialized")

+ 22 - 0
models/node.go

@@ -54,6 +54,8 @@ type Node struct {
 	IsRelayed           string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
 	IsRelayed           string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
 	IsPending           string   `json:"ispending" bson:"ispending" yaml:"ispending"`
 	IsPending           string   `json:"ispending" bson:"ispending" yaml:"ispending"`
 	IsRelay             string   `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
 	IsRelay             string   `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
+	IsDocker            string   `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
+	IsK8S               string   `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
 	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
 	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
 	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
 	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
 	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
 	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
@@ -122,6 +124,20 @@ func (node *Node) SetDefaultIsRelay() {
 	}
 	}
 }
 }
 
 
+// Node.SetDefaultIsDocker - set default isdocker
+func (node *Node) SetDefaultIsDocker() {
+	if node.IsDocker == "" {
+		node.IsDocker = "no"
+	}
+}
+
+// Node.SetDefaultIsK8S - set default isk8s
+func (node *Node) SetDefaultIsK8S() {
+	if node.IsK8S == "" {
+		node.IsK8S = "no"
+	}
+}
+
 // Node.SetDefaultEgressGateway - sets default egress gateway status
 // Node.SetDefaultEgressGateway - sets default egress gateway status
 func (node *Node) SetDefaultEgressGateway() {
 func (node *Node) SetDefaultEgressGateway() {
 	if node.IsEgressGateway == "" {
 	if node.IsEgressGateway == "" {
@@ -381,6 +397,12 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.IsRelayed == "" {
 	if newNode.IsRelayed == "" {
 		newNode.IsRelayed = currentNode.IsRelayed
 		newNode.IsRelayed = currentNode.IsRelayed
 	}
 	}
+	if newNode.IsDocker == "" {
+		newNode.IsDocker = currentNode.IsDocker
+	}
+	if newNode.IsK8S == "" {
+		newNode.IsK8S = currentNode.IsK8S
+	}
 	if newNode.Version == "" {
 	if newNode.Version == "" {
 		newNode.Version = currentNode.Version
 		newNode.Version = currentNode.Version
 	}
 	}

+ 6 - 0
models/structs.go

@@ -163,3 +163,9 @@ type ServerUpdateData struct {
 	UpdatePeers bool `json:"updatepeers" bson:"updatepeers"`
 	UpdatePeers bool `json:"updatepeers" bson:"updatepeers"`
 	Node        Node `json:"servernode" bson:"servernode"`
 	Node        Node `json:"servernode" bson:"servernode"`
 }
 }
+
+// Telemetry - contains UUID of the server and timestamp of last send to posthog
+type Telemetry struct {
+	UUID     string `json:"uuid" bson:"uuid"`
+	LastSend int64  `json:"lastsend" bson:"lastsend"`
+}

+ 13 - 0
servercfg/serverconf.go

@@ -86,6 +86,7 @@ func GetServerConfig() config.ServerConfig {
 		cfg.RCE = "off"
 		cfg.RCE = "off"
 	}
 	}
 	cfg.Debug = GetDebug()
 	cfg.Debug = GetDebug()
+	cfg.Telemetry = Telemetry()
 
 
 	return cfg
 	return cfg
 }
 }
@@ -356,6 +357,18 @@ func IsClientMode() string {
 	return isclient
 	return isclient
 }
 }
 
 
+// Telemetry - checks if telemetry data should be sent
+func Telemetry() string {
+	telemetry := "on"
+	if os.Getenv("TELEMETRY") == "off" {
+		telemetry = "off"
+	}
+	if config.Config.Server.Telemetry == "off" {
+		telemetry = "off"
+	}
+	return telemetry
+}
+
 // IsDNSMode - should it run with DNS
 // IsDNSMode - should it run with DNS
 func IsDNSMode() bool {
 func IsDNSMode() bool {
 	isdns := true
 	isdns := true

+ 181 - 0
serverctl/telemetry.go

@@ -0,0 +1,181 @@
+package serverctl
+
+import (
+	"encoding/json"
+	"time"
+
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
+	"github.com/posthog/posthog-go"
+)
+
+// POSTHOG_PUB_KEY - Key for sending data to PostHog
+const POSTHOG_PUB_KEY = "phc_1vEXhPOA1P7HP5jP2dVU9xDTUqXHAelmtravyZ1vvES"
+
+// POSTHOG_ENDPOINT - Endpoint of PostHog server
+const POSTHOG_ENDPOINT = "https://app.posthog.com"
+
+// TELEMETRY_HOURS_BETWEEN_SEND - How long to wait before sending telemetry to server (24 hours)
+const TELEMETRY_HOURS_BETWEEN_SEND = 24
+
+// TelemetryCheckpoint - Checks if 24 hours has passed since telemetry was last sent. If so, sends telemetry data to posthog
+func TelemetryCheckpoint() error {
+
+	// if telemetry is turned off, return without doing anything
+	if servercfg.Telemetry() == "off" {
+		return nil
+	}
+	// get the telemetry record in the DB, which contains a timestamp
+	telRecord, err := fetchTelemetryRecord()
+	if err != nil {
+		return err
+	}
+	sendtime := time.Unix(telRecord.LastSend, 0).Add(time.Hour * time.Duration(TELEMETRY_HOURS_BETWEEN_SEND))
+	// can set to 2 minutes for testing
+	//sendtime := time.Unix(telRecord.LastSend, 0).Add(time.Minute * 2)
+	enoughTimeElapsed := time.Now().After(sendtime)
+	// if more than 24 hours has elapsed, send telemetry to posthog
+	if enoughTimeElapsed {
+		err = sendTelemetry(telRecord.UUID)
+		if err != nil {
+			logger.Log(1, err.Error())
+		}
+	}
+	return nil
+}
+
+// sendTelemetry - gathers telemetry data and sends to posthog
+func sendTelemetry(serverUUID string) error {
+	// get telemetry data
+	d, err := fetchTelemetryData()
+	if err != nil {
+		return err
+	}
+	client, err := posthog.NewWithConfig(POSTHOG_PUB_KEY, posthog.Config{Endpoint: POSTHOG_ENDPOINT})
+	if err != nil {
+		return err
+	}
+	defer client.Close()
+
+	// send to posthog
+	err = client.Enqueue(posthog.Capture{
+		DistinctId: serverUUID,
+		Event:      "daily checkin",
+		Properties: posthog.NewProperties().
+			Set("nodes", d.Nodes).
+			Set("non-server nodes", d.Count.NonServer).
+			Set("extclients", d.ExtClients).
+			Set("users", d.Users).
+			Set("networks", d.Networks).
+			Set("linux", d.Count.Linux).
+			Set("darwin", d.Count.MacOS).
+			Set("windows", d.Count.Windows).
+			Set("freebsd", d.Count.FreeBSD).
+			Set("docker", d.Count.Docker).
+			Set("k8s", d.Count.K8S).
+			Set("version", d.Version),
+	})
+	if err != nil {
+		return err
+	}
+	//set telemetry timestamp for server, restarts 24 hour cycle
+	return setTelemetryTimestamp(serverUUID)
+}
+
+// fetchTelemetry - fetches telemetry data: count of various object types in DB
+func fetchTelemetryData() (telemetryData, error) {
+	var data telemetryData
+
+	data.ExtClients = getDBLength(database.EXT_CLIENT_TABLE_NAME)
+	data.Users = getDBLength(database.USERS_TABLE_NAME)
+	data.Networks = getDBLength(database.NETWORKS_TABLE_NAME)
+	data.Version = servercfg.GetVersion()
+	nodes, err := logic.GetAllNodes()
+	if err == nil {
+		data.Nodes = len(nodes)
+		data.Count = getClientCount(nodes)
+	}
+	return data, err
+}
+
+// setTelemetryTimestamp - Give the entry in the DB a new timestamp
+func setTelemetryTimestamp(uuid string) error {
+	lastsend := time.Now().Unix()
+	var serverTelData = models.Telemetry{
+		UUID:     uuid,
+		LastSend: lastsend,
+	}
+	jsonObj, err := json.Marshal(serverTelData)
+	if err != nil {
+		return err
+	}
+	err = database.Insert(database.SERVER_UUID_RECORD_KEY, string(jsonObj), database.SERVER_UUID_TABLE_NAME)
+	return err
+}
+
+// getClientCount - returns counts of nodes with various OS types and conditions
+func getClientCount(nodes []models.Node) clientCount {
+	var count clientCount
+	for _, node := range nodes {
+		switch node.OS {
+		case "macos":
+			count.MacOS += 1
+		case "windows":
+			count.Windows += 1
+		case "linux":
+			count.Linux += 1
+		case "freebsd":
+			count.FreeBSD += 1
+		}
+		if !(node.IsServer == "yes") {
+			count.NonServer += 1
+		}
+	}
+	return count
+}
+
+// fetchTelemetryRecord - get the existing UUID and Timestamp from the DB
+func fetchTelemetryRecord() (models.Telemetry, error) {
+	var rawData string
+	var telObj models.Telemetry
+	var err error
+	rawData, err = database.FetchRecord(database.SERVER_UUID_TABLE_NAME, database.SERVER_UUID_RECORD_KEY)
+	if err != nil {
+		return telObj, err
+	}
+	err = json.Unmarshal([]byte(rawData), &telObj)
+	return telObj, err
+}
+
+// getDBLength - get length of DB to get count of objects
+func getDBLength(dbname string) int {
+	data, err := database.FetchRecords(dbname)
+	if err != nil {
+		return 0
+	}
+	return len(data)
+}
+
+// telemetryData - What data to send to posthog
+type telemetryData struct {
+	Nodes      int
+	ExtClients int
+	Users      int
+	Count      clientCount
+	Networks   int
+	Version    string
+}
+
+// clientCount - What types of netclients we're tallying
+type clientCount struct {
+	MacOS     int
+	Windows   int
+	Linux     int
+	FreeBSD   int
+	K8S       int
+	Docker    int
+	NonServer int
+}

Some files were not shown because too many files changed in this diff