Browse Source

Merge pull request #212 from gravitl/v0.7.1

V0.7.1
Alex 4 years ago
parent
commit
6227f0040c
100 changed files with 5454 additions and 4869 deletions
  1. 1 0
      .gitignore
  2. 2 3
      Dockerfile
  3. 26 0
      Dockerfile-netclient
  4. 12 0
      compose/docker-compose.coredns.yml
  5. 27 24
      compose/docker-compose.nodns.yml
  6. 70 0
      compose/docker-compose.quickstart.yml
  7. 133 0
      compose/docker-compose.reference copy.yml
  8. 16 32
      compose/docker-compose.reference.yml
  9. 48 0
      compose/docker-compose.test.yml
  10. 45 63
      config/config.go
  11. 0 8
      config/dnsconfig/Corefile
  12. 0 1
      config/dnsconfig/netmaker.hosts
  13. 1 17
      config/environments/dev.yaml
  14. 107 100
      controllers/authGrpc.go
  15. 175 429
      controllers/common.go
  16. 11 19
      controllers/common_test.go
  17. 2 8
      controllers/config/environments/dev.yaml
  18. 44 48
      controllers/controller.go
  19. 90 150
      controllers/dnsHttpController.go
  20. 4 6
      controllers/dnsHttpController_test.go
  21. 172 225
      controllers/extClientHttpController.go
  22. 0 207
      controllers/intClientHttpController.go
  23. 257 394
      controllers/networkHttpController.go
  24. 13 19
      controllers/networkHttpController_test.go
  25. 106 370
      controllers/nodeGrpcController.go
  26. 252 352
      controllers/nodeHttpController.go
  27. 7 14
      controllers/nodeHttpController_test.go
  28. 13 24
      controllers/serverHttpController.go
  29. 208 123
      controllers/userHttpController.go
  30. 16 20
      controllers/userHttpController_test.go
  31. 135 0
      database/database.go
  32. 54 0
      database/statics.go
  33. BIN
      docs/_build/doctrees/architecture.doctree
  34. BIN
      docs/_build/doctrees/client-installation.doctree
  35. BIN
      docs/_build/doctrees/environment.pickle
  36. BIN
      docs/_build/doctrees/external-clients.doctree
  37. BIN
      docs/_build/doctrees/getting-started.doctree
  38. BIN
      docs/_build/doctrees/index.doctree
  39. BIN
      docs/_build/doctrees/quick-start.doctree
  40. BIN
      docs/_build/doctrees/server-installation.doctree
  41. BIN
      docs/_build/doctrees/support.doctree
  42. BIN
      docs/_build/doctrees/troubleshoot.doctree
  43. BIN
      docs/_build/doctrees/usage.doctree
  44. 1 1
      docs/_build/html/.buildinfo
  45. BIN
      docs/_build/html/_images/create-net.png
  46. BIN
      docs/_build/html/_images/exclient1.png
  47. BIN
      docs/_build/html/_images/exclient2.png
  48. BIN
      docs/_build/html/_images/exclient3.png
  49. BIN
      docs/_build/html/_images/exclient4.png
  50. BIN
      docs/_build/html/_images/netmaker-node.png
  51. 39 27
      docs/_build/html/_sources/architecture.rst.txt
  52. 27 2
      docs/_build/html/_sources/client-installation.rst.txt
  53. 40 0
      docs/_build/html/_sources/external-clients.rst.txt
  54. 112 134
      docs/_build/html/_sources/getting-started.rst.txt
  55. 5 0
      docs/_build/html/_sources/index.rst.txt
  56. 131 93
      docs/_build/html/_sources/quick-start.rst.txt
  57. 200 239
      docs/_build/html/_sources/server-installation.rst.txt
  58. 6 20
      docs/_build/html/_sources/support.rst.txt
  59. 75 1
      docs/_build/html/_sources/troubleshoot.rst.txt
  60. 3 18
      docs/_build/html/_sources/usage.rst.txt
  61. 1 1
      docs/_build/html/_static/documentation_options.js
  62. 54 19
      docs/_build/html/about.html
  63. 54 19
      docs/_build/html/api.html
  64. 86 41
      docs/_build/html/architecture.html
  65. 80 72
      docs/_build/html/client-installation.html
  66. 54 19
      docs/_build/html/conduct.html
  67. 54 19
      docs/_build/html/contribute.html
  68. 90 19
      docs/_build/html/external-clients.html
  69. 46 53
      docs/_build/html/genindex.html
  70. 611 176
      docs/_build/html/getting-started.html
  71. 70 72
      docs/_build/html/index.html
  72. 54 19
      docs/_build/html/license.html
  73. BIN
      docs/_build/html/objects.inv
  74. 230 121
      docs/_build/html/quick-start.html
  75. 46 53
      docs/_build/html/search.html
  76. 0 0
      docs/_build/html/searchindex.js
  77. 321 375
      docs/_build/html/server-installation.html
  78. 60 66
      docs/_build/html/support.html
  79. 122 26
      docs/_build/html/troubleshoot.html
  80. 57 97
      docs/_build/html/usage.html
  81. 39 27
      docs/architecture.rst
  82. 27 2
      docs/client-installation.rst
  83. 1 1
      docs/conf.py
  84. 10 0
      docs/examplecode/myclient.conf
  85. 5 3
      docs/examplecode/netclient-join.txt
  86. 10 7
      docs/examplecode/netconfig-example.yml
  87. 40 0
      docs/external-clients.rst
  88. 126 0
      docs/getting-started.rst
  89. BIN
      docs/images/create-net.png
  90. BIN
      docs/images/exclient1.png
  91. BIN
      docs/images/exclient2.png
  92. BIN
      docs/images/exclient3.png
  93. BIN
      docs/images/exclient4.png
  94. BIN
      docs/images/netmaker-node.png
  95. 5 0
      docs/index.rst
  96. 131 93
      docs/quick-start.rst
  97. 200 239
      docs/server-installation.rst
  98. 6 20
      docs/support.rst
  99. 75 1
      docs/troubleshoot.rst
  100. 3 18
      docs/usage.rst

+ 1 - 0
.gitignore

@@ -1,3 +1,4 @@
 netmaker
 netclient/netclient
 netclient/files/netclient
+config/dnsconfig/

+ 2 - 3
Dockerfile

@@ -8,13 +8,13 @@ WORKDIR /app
 
 ENV GO111MODULE=auto
 
-RUN CGO_ENABLED=0 GOOS=linux go build -o app main.go
+RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o app main.go
 
 WORKDIR /app/netclient
 
 ENV GO111MODULE=auto
 
-RUN CGO_ENABLED=0 GOOS=linux go build -o netclient main.go
+RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o netclient main.go
 
 #second stage
 
@@ -34,4 +34,3 @@ EXPOSE 8081
 EXPOSE 50051
 
 CMD ["./app"]
-

+ 26 - 0
Dockerfile-netclient

@@ -0,0 +1,26 @@
+#first stage - builder
+
+FROM golang:latest as builder
+
+COPY . /app
+
+WORKDIR /app/netclient
+
+ENV GO111MODULE=auto
+
+RUN CGO_ENABLED=0 GOOS=linux go build -o netclient main.go
+
+#second stage
+
+FROM debian:latest
+
+RUN apt-get update && apt-get -y install systemd procps
+
+WORKDIR /root/
+
+COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
+
+COPY --from=builder /app/netclient/netclient .
+
+CMD ["./netclient"]
+

+ 12 - 0
compose/docker-compose.coredns.yml

@@ -0,0 +1,12 @@
+version: "3.4"
+
+services:
+  coredns:
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile
+    container_name: coredns
+    restart: always
+    ports:
+      - "53:53/udp"
+    volumes:
+      - /root/netmaker/config/dnsconfig:/root/dnsconfig

+ 27 - 24
compose/docker-compose.nodns.yml

@@ -1,53 +1,56 @@
 version: "3.4"
 
-volumes:
-  dnsconfig:
-  driver: local
 services:
-  mongodb:
-    image: mongo:4.2
-    ports:
-      - "27017:27017"
-    container_name: mongodb
-    volumes:
-      - mongovol:/data/db
+  rqlite:
+    container_name: rqlite
+    image: rqlite/rqlite
+    network_mode: host
     restart: always
-    environment:
-      MONGO_INITDB_ROOT_USERNAME: mongoadmin
-      MONGO_INITDB_ROOT_PASSWORD: mongopass
+    volumes:
+      - sqldata:/rqlite/file/data
   netmaker:
+    depends_on:
+      - rqlite
     privileged: true
     container_name: netmaker
-    depends_on:
-      - mongodb
-    image: gravitl/netmaker:v0.5
+    image: gravitl/netmaker:v0.7
     volumes:
       - ./:/local
       - /etc/netclient:/etc/netclient
-      - dnsconfig:/root/config/dnsconfig
-      - /usr/bin/wg:/usr/bin/wg:ro
+      - /usr/bin/wg:/usr/bin/wg
       - /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
-    cap_add:
+    cap_add: 
       - NET_ADMIN
       - SYS_MODULE
     restart: always
     network_mode: host
     environment:
+      SERVER_HOST: "SERVER_PUBLIC_IP"
       DNS_MODE: "off"
+      SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
+      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443"
+      GRPC_SSL: "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: "*"
   netmaker-ui:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.5
+    image: gravitl/netmaker-ui:v0.7
     links:
       - "netmaker:api"
     ports:
-      - "80:80"
+      - "8082:80"
     environment:
-      BACKEND_URL: "http://HOST_IP:8081"
+      BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN"
 volumes:
-  mongovol: {}
-  dnsconfig: {}
+  sqldata: {}

+ 70 - 0
compose/docker-compose.quickstart.yml

@@ -0,0 +1,70 @@
+version: "3.4"
+
+services:
+  rqlite:
+    container_name: rqlite
+    image: rqlite/rqlite
+    network_mode: host
+    restart: always
+    volumes:
+      - sqldata:/rqlite/file/data
+  netmaker:
+    depends_on:
+      - rqlite
+    privileged: true
+    container_name: netmaker
+    image: gravitl/netmaker:v0.7
+    volumes:
+      - ./:/local
+      - /etc/netclient:/etc/netclient
+      - dnsconfig:/root/config/dnsconfig
+      - /usr/bin/wg:/usr/bin/wg
+      - /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
+    cap_add: 
+      - NET_ADMIN
+      - SYS_MODULE
+    restart: always
+    network_mode: host
+    environment:
+      SERVER_HOST: "SERVER_PUBLIC_IP"
+      SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
+      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:1443"
+      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: "*"
+  netmaker-ui:
+    container_name: netmaker-ui
+    depends_on:
+      - netmaker
+    image: gravitl/netmaker-ui:v0.7
+    links:
+      - "netmaker:api"
+    ports:
+      - "8082:80"
+    environment:
+      BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN"
+  coredns:
+    depends_on:
+      - netmaker 
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile
+    container_name: coredns
+    restart: always
+    ports:
+      - "53:53/udp"
+    volumes:
+      - dnsconfig:/root/dnsconfig
+volumes:
+  sqldata: {}
+  dnsconfig: {}

+ 133 - 0
compose/docker-compose.reference copy.yml

@@ -0,0 +1,133 @@
+services:
+  rqlite:
+    container_name: rqlite
+    image: rqlite/rqlite
+    network_mode: host
+    restart: always
+    volumes:
+      - sqldata:/rqlite/file/data
+  netmaker:
+    depends_on:
+      - rqlite
+    privileged: true
+    container_name: netmaker
+    image: gravitl/netmaker:v0.7
+    volumes:
+      - ./:/local
+      - /etc/netclient:/etc/netclient
+      - dnsconfig:/root/config/dnsconfig
+      - /usr/bin/wg:/usr/bin/wg
+      - /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
+    cap_add: 
+      - NET_ADMIN
+      - SYS_MODULE
+    restart: always
+    network_mode: host
+    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"
+      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: "*"
+  netmaker-ui:
+    container_name: netmaker-ui
+    depends_on:
+      - netmaker
+    image: gravitl/netmaker-ui:v0.7
+    links:
+      - "netmaker:api"
+    ports:
+      - "8082:80"
+    environment:
+      BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN"
+  coredns:
+    depends_on:
+      - netmaker 
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile
+    container_name: coredns
+    restart: always
+    ports:
+      - "53:53/udp"
+    volumes:
+      - dnsconfig:/root/dnsconfig
+
+
+version: "3.4"
+
+services:
+  rqlite: # The rqlite instance that backs up Netmaker
+    container_name: rqlite
+    image: rqlite/rqlite
+    network_mode: host
+    restart: always
+    volumes:
+      - sqldata:/rqlite/file/data
+  netmaker: # The Primary Server for running Netmaker
+    privileged: true # Necessary to run sudo/root level commands on host system. Take out if not running with CLIENT_MODE=on
+    container_name: netmaker
+    depends_on:
+      - mongodb
+    image: gravitl/netmaker:v0.7
+    volumes: # Volume mounts necessary for Netmaker to control netclient, wireguard, and networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
+      - ./:/local
+      - /etc/netclient:/etc/netclient
+      - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
+      - /usr/bin/wg:/usr/bin/wg
+      - /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
+    cap_add: # Necessary for CLIENT_MODE. Should be removed if turned off. 
+      - NET_ADMIN
+      - SYS_MODULE
+    restart: always
+    network_mode: host # Necessary for CLIENT_MODE. Should be removed if turned off, but then need to add port mappings
+    environment:
+      GRPC_SSL: "off" # Tells clients to use SSL to connect to GRPC. Switch to on to turn on.
+      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_HOST: "" # All the Docker Compose files pre-populate this with HOST_IP, which you replace as part of the install instructions. This will set both HTTP and GRPC host.
+      API_PORT: 8081 # The HTTP API port for Netmaker. Used for API calls / communication from front end. If changed, need to change port of BACKEND_URL for netmaker-ui.
+      GRPC_PORT: 50051 # The GRPC port for Netmaker. Used for communications from nodes.
+      MASTER_KEY: "secretkey" # The admin master key for accessing the API. Change this in any production installation.
+      CORS_ALLOWED_ORIGIN: "*" # The "allowed origin" for API requests. Change to restrict where API requests can come from.
+      REST_BACKEND: "on" # Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
+      AGENT_BACKEND: "on" # Enables the AGENT backend (GRPC running on GRPC_PORT at SERVER_GRPC_HOST). Change to "off" to turn off.
+      DNS_MODE: "on" # Enables DNS Mode, meaning config files will be generated for CoreDNS. Note, turning "off" does not remove CoreDNS. You still need to remove CoreDNS from compose file.
+  netmaker-ui: # The Netmaker UI Component
+    container_name: netmaker-ui
+    depends_on:
+      - netmaker
+    image: gravitl/netmaker-ui:v0.7
+    links:
+      - "netmaker:api"
+    ports:
+      - "8082:80"
+    environment:
+      BACKEND_URL: "http://HOST_IP:8081" # URL where UI will send API requests. Change based on SERVER_HOST, SERVER_HTTP_HOST, and API_PORT
+  coredns: # The DNS Server. Remove this section if DNS_MODE="off"
+    depends_on:
+      - netmaker 
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile # Config location for Corefile. This is the path of file which is also mounted to Netmaker for modification.
+    container_name: coredns
+    restart: always
+    ports:
+      - "53:53/udp" # Likely needs to run at port 53 for adequate nameserver usage.
+    volumes:
+      - dnsconfig:/root/dnsconfig
+volumes:
+  sqldata: {}
+  dnsconfig: {}

+ 16 - 32
compose/docker-compose.reference.yml

@@ -1,23 +1,17 @@
-version: "3.4"
-
 services:
-  mongodb: # The MongoDB Instance that backs up Netmaker
-    image: mongo:4.2
-    ports:
-      - "27017:27017" # Port Mapping for MongoDB. Can be modified, but be sure to change the MONGO_PORT env var in netmaker
-    container_name: mongodb
-    volumes:
-      - mongovol:/data/db
+  rqlite:
+    container_name: rqlite
+    image: rqlite/rqlite
+    network_mode: host
     restart: always
-    environment:
-      MONGO_INITDB_ROOT_USERNAME: mongoadmin # Default username. Recommend changing for production installs. You will need to set MONGO_ADMIN netmaker env var.
-      MONGO_INITDB_ROOT_PASSWORD: mongopass # Default password. Recommend changing for production installs. You will need to set MONGO_PASS netmaker env var.
+    volumes:
+      - sqldata:/rqlite/file/data
   netmaker: # The Primary Server for running Netmaker
     privileged: true # Necessary to run sudo/root level commands on host system. Take out if not running with CLIENT_MODE=on
     container_name: netmaker
     depends_on:
-      - mongodb
-    image: gravitl/netmaker:v0.5
+      - rqlite
+    image: gravitl/netmaker:v0.7
     volumes: # Volume mounts necessary for CLIENT_MODE to control netclient, wireguard, and networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
       - ./:/local
       - /etc/netclient:/etc/netclient
@@ -42,33 +36,23 @@ services:
       CORS_ALLOWED_ORIGIN: "*" # The "allowed origin" for API requests. Change to restrict where API requests can come from.
       REST_BACKEND: "on" # Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
       AGENT_BACKEND: "on" # Enables the AGENT backend (GRPC running on GRPC_PORT at SERVER_GRPC_HOST). Change to "off" to turn off.
-      CLIENT_MODE: "on" # Enables Client Mode, meaning netclient will be deployed on server and will be manageable from UI. Change to "off" to turn off.
       DNS_MODE: "on" # Enables DNS Mode, meaning config files will be generated for CoreDNS. Note, turning "off" does not remove CoreDNS. You still need to remove CoreDNS from compose file.
       DISABLE_REMOTE_IP_CHECK: "off" # If turned "on", Server will not set Host based on remote IP check. This is already overridden if SERVER_HOST is set. Turned "off" by default.
-      MONGO_ADMIN: "mongoadmin" # Admin user for MongoDB. Change to match above MongoDB instance
-      MONGO_PASS: "mongopass" # Admin password for MongoDB. Change to match above MongoDB instance
-      MONGO_HOST: "127.0.0.1" # Address of MongoDB. Change if necessary.
-      MONGO_PORT: "27017" # Port of MongoDB. Change if necessary.
-      MONGO_OPTS: "/?authSource=admin" # Opts to enable admin login for Mongo.
-      SERVER_GRPC_WIREGUARD: "on" # Whether to run GRPC over a WireGuard network. On by default. Secures server comms. Switch to "off" to turn off.
-      SERVER_GRPC_WG_INTERFACE: "nm-grpc-wg" # Interface to use for GRPC WireGuard network if enabled
-      SERVER_GRPC_WG_ADDRESS: "10.101.0.1" # Private Address to use for GRPC WireGuard network if enabled
-      SERVER_GRPC_WG_ADDRESS_RANGE: "10.101.0.0/16" # Private Address range to use for GRPC WireGard clients if enabled
-      SERVER_GRPC_WG_PORT: "50555" # Port to use for GRPC WireGuard if enabled
-      SERVER_GRPC_WG_PUBKEY: "SERVER_GRPC_WG_PUBKEY" # PublicKey for GRPC WireGuard interface. Generated if blank.
-      SERVER_GRPC_WG_PRIVKEY: "SERVER_GRPC_WG_PRIVKEY" # PrivateKey for GRPC WireGuard interface. Generated if blank.
+      GRPC_SSL: "off" # Tells clients to use SSL to connect to GRPC. Switch to on to turn on.
+      COREDNS_ADDR: "" # Address of the CoreDNS server. Defaults to SERVER_HOST
+      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
   netmaker-ui: # The Netmaker UI Component
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.5
+    image: gravitl/netmaker-ui:v0.7
     links:
       - "netmaker:api"
     ports:
-      - "80:80"
+      - "8082:80"
     environment:
       BACKEND_URL: "http://HOST_IP:8081" # URL where UI will send API requests. Change based on SERVER_HOST, SERVER_HTTP_HOST, and API_PORT
-      MASTER_KEY: "secretkey" # Master Key for API calls. Will be removed in v0.3.5
   coredns: # The DNS Server. Remove this section if DNS_MODE="off"
     depends_on:
       - netmaker 
@@ -81,5 +65,5 @@ services:
     volumes:
       - dnsconfig:/root/dnsconfig
 volumes:
-  mongovol: {}
-  dnsconfig: {}
+  sqldata: {}
+  dnsconfig: {}

+ 48 - 0
compose/docker-compose.test.yml

@@ -0,0 +1,48 @@
+version: "3.4"
+
+services:
+  rqlite:
+    container_name: rqlite
+    image: rqlite/rqlite
+    network_mode: host
+    restart: always
+    volumes:
+      - sqldata:/rqlite/file/data
+  netmaker:
+    depends_on:
+      - rqlite
+    privileged: true
+    container_name: netmaker
+    image: gravitl/netmaker:v0.7
+    volumes:
+      - ./:/local
+      - /etc/netclient:/etc/netclient
+      - /usr/bin/wg:/usr/bin/wg
+      - /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
+    cap_add: 
+      - NET_ADMIN
+      - SYS_MODULE
+    restart: always
+    network_mode: host
+    environment:
+      GRPC_SSL: "off"
+      API_PORT: "8081"
+      GRPC_PORT: "50051"
+      DNS_MODE: "off"
+      CORS_ALLOWED_ORIGIN: "*"
+  netmaker-ui:
+    container_name: netmaker-ui
+    depends_on:
+      - netmaker
+    image: gravitl/netmaker-ui:v0.7
+    links:
+      - "netmaker:api"
+    ports:
+      - "80:80"
+    environment:
+      BACKEND_URL: "http://HOST_IP:8081"
+volumes:
+  sqldata: {}

+ 45 - 63
config/config.go

@@ -2,26 +2,26 @@
 //Currently the only thing it does is set the master password
 //Should probably have it take over functions from OS such as port and mongodb connection details
 //Reads from the config/environments/dev.yaml file by default
-//TODO:  Add vars for mongo and remove from  OS vars in mongoconn
 package config
 
 import (
-  "os"
-  "fmt"
-  "log"
-  "gopkg.in/yaml.v3"
+	"fmt"
+	"log"
+	"os"
+
+	"gopkg.in/yaml.v3"
 )
 
 //setting dev by default
 func getEnv() string {
 
-  env := os.Getenv("NETMAKER_ENV")
+	env := os.Getenv("NETMAKER_ENV")
 
-  if len(env) == 0 {
-    return "dev"
-  }
+	if len(env) == 0 {
+		return "dev"
+	}
 
-  return env
+	return env
 }
 
 // Config : application config stored as global variable
@@ -29,70 +29,52 @@ var Config *EnvironmentConfig
 
 // EnvironmentConfig :
 type EnvironmentConfig struct {
-  Server ServerConfig `yaml:"server"`
-  MongoConn MongoConnConfig `yaml:"mongoconn"`
-  WG WG `yaml:"wg"`
+	Server ServerConfig `yaml:"server"`
 }
 
 // ServerConfig :
 type ServerConfig struct {
-  APIHost   string  `yaml:"apihost"`
-  APIPort   string `yaml:"apiport"`
-  GRPCHost   string `yaml:"grpchost"`
-  GRPCPort   string `yaml:"grpcport"`
-  MasterKey	string `yaml:"masterkey"`
-  AllowedOrigin	string `yaml:"allowedorigin"`
-  RestBackend string `yaml:"restbackend"`
-  AgentBackend string `yaml:"agentbackend"`
-  ClientMode string `yaml:"clientmode"`
-  DNSMode string `yaml:"dnsmode"`
-  DisableRemoteIPCheck string `yaml:"disableremoteipcheck"`
-}
-
-type WG struct {
-  RegisterKeyRequired  string  `yaml:"keyrequired"`
-  GRPCWireGuard  string  `yaml:"grpcwg"`
-  GRPCWGInterface  string `yaml:"grpciface"`
-  GRPCWGAddress  string `yaml:"grpcaddr"`
-  GRPCWGAddressRange  string `yaml:"grpcaddrrange"`
-  GRPCWGPort  string  `yaml:"grpcport"`
-  GRPCWGPubKey  string  `yaml:"pubkey"`
-  GRPCWGPrivKey  string  `yaml:"privkey"`
+	CoreDNSAddr          string `yaml:"corednsaddr"`
+	APIConnString        string `yaml:"apiconn"`
+	APIHost              string `yaml:"apihost"`
+	APIPort              string `yaml:"apiport"`
+	GRPCConnString       string `yaml:"grpcconn"`
+	GRPCHost             string `yaml:"grpchost"`
+	GRPCPort             string `yaml:"grpcport"`
+	GRPCSecure           string `yaml:"grpcsecure"`
+	DefaultNodeLimit     int32  `yaml:"defaultnodelimit"`
+	MasterKey            string `yaml:"masterkey"`
+	AllowedOrigin        string `yaml:"allowedorigin"`
+	RestBackend          string `yaml:"restbackend"`
+	AgentBackend         string `yaml:"agentbackend"`
+	ClientMode           string `yaml:"clientmode"`
+	DNSMode              string `yaml:"dnsmode"`
+	DisableRemoteIPCheck string `yaml:"disableremoteipcheck"`
+	DisableDefaultNet    string `yaml:"disabledefaultnet"`
+	GRPCSSL              string `yaml:"grpcssl"`
+	Verbosity            int32  `yaml:"verbosity"`
 }
 
-type MongoConnConfig struct {
-  User   string  `yaml:"user"`
-  Pass   string  `yaml:"pass"`
-  Host   string  `yaml:"host"`
-  Port   string  `yaml:"port"`
-  Opts   string  `yaml:"opts"`
-}
-
-
 //reading in the env file
 func readConfig() *EnvironmentConfig {
-  file := fmt.Sprintf("config/environments/%s.yaml", getEnv())
-  f, err := os.Open(file)
-  var cfg EnvironmentConfig
-  if err != nil {
-    //log.Fatal(err)
-    //os.Exit(2)
-    //log.Println("Unable to open config file at config/environments/" + getEnv())
-    //log.Println("Will proceed with defaults or enironment variables (no config file).")
-    return &cfg
-  }
-  defer f.Close()
+	file := fmt.Sprintf("config/environments/%s.yaml", getEnv())
+	f, err := os.Open(file)
+	var cfg EnvironmentConfig
+	if err != nil {
+		return &cfg
+	}
+	defer f.Close()
 
-  decoder := yaml.NewDecoder(f)
-  err = decoder.Decode(&cfg)
-  if err != nil {
-    log.Fatal(err)
-    os.Exit(2)
-  }
-  return &cfg
+	decoder := yaml.NewDecoder(f)
+	err = decoder.Decode(&cfg)
+	if err != nil {
+		log.Fatal(err)
+		os.Exit(2)
+	}
+	return &cfg
 
 }
 
 func init() {
-  Config = readConfig()
+	Config = readConfig()
 }

+ 0 - 8
config/dnsconfig/Corefile

@@ -1,8 +0,0 @@
-default comms  {
-    reload 15s
-    hosts /root/dnsconfig/netmaker.hosts {
-	fallthrough	
-    }
-    forward . 8.8.8.8 8.8.4.4
-    log
-}

+ 0 - 1
config/dnsconfig/netmaker.hosts

@@ -1 +0,0 @@
-10.10.10.1       netmaker.default

+ 1 - 17
config/environments/dev.yaml

@@ -9,20 +9,4 @@ server:
   agentbackend: "" # defaults to "on" or AGENT_BACKEND (if set)
   clientmode: "" # defaults to "on" or CLIENT_MODE (if set)
   dnsmode: "" # defaults to "on" or DNS_MODE (if set)
-  disableremoteipcheck: "" # defaults to "false" or DISABLE_REMOTE_IP_CHECK (if set)
-mongoconn:
-  user: "" # defaults to "mongoadmin" or MONGO_ADMIN (if set)
-  pass: "" # defaults to "mongopass" or MONGO_PASS (if set)
-  host: "" # defaults to 127.0.0.1 or MONGO_HOST (if set)
-  port: "" # defaults to 27017 or MONGO_PORT (if set)
-  opts: '' # defaults to '/?authSource=admin' or MONGO_OPTS (if set)
-wg:
-  keyrequired: "" # defaults to "". If set to "yes", a key is required for signing up for the comms network 
-  grpcwg: "" # defaults to "on" or SERVER_GRPC_WIREGUARD if set
-  grpciface: "" # defaults to nm-grpc-wg or SERVER_GRPC_WG_INTERFACE if set
-  grpcaddr: "" # defaults to 10.101.0.1 or SERVER_GRPC_WG_ADDRESS if set
-  grpcaddrrange: "" # defaults to 10.101.0.0/16 or SERVER_GRPC_WG_ADDRESS_RANGE if set
-  grpcendpoint: "" # defaults to SERVER_HOST if unset
-  grpcport: "" # defaults to 50555 or SERVER_GRPC_WG_PORT if set
-  pubkey: "" # defaults to generated value or SERVER_GRPC_WG_PUBKEY if set
-  privkey: "" # defaults to generated value or SERVER_GRPC_WG_PRIVKEY if set
+  disableremoteipcheck: "" # defaults to "false" or DISABLE_REMOTE_IP_CHECK (if set)

+ 107 - 100
controllers/authGrpc.go

@@ -1,20 +1,19 @@
 package controller
 
 import (
-	"errors"
 	"context"
-        "golang.org/x/crypto/bcrypt"
-        "time"
-        nodepb "github.com/gravitl/netmaker/grpc"
-        "github.com/gravitl/netmaker/models"
-        "github.com/gravitl/netmaker/functions"
-        "github.com/gravitl/netmaker/mongoconn"
-        "go.mongodb.org/mongo-driver/bson"
+	"encoding/json"
+	"errors"
+
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/functions"
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/models"
+	"golang.org/x/crypto/bcrypt"
 	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/metadata"
 	"google.golang.org/grpc/status"
-	"google.golang.org/grpc/codes"
-
 )
 
 func AuthServerUnaryInterceptor(ctx context.Context,
@@ -24,15 +23,14 @@ func AuthServerUnaryInterceptor(ctx context.Context,
 	// Skip authorize when GetJWT is requested
 
 	if info.FullMethod != "/node.NodeService/Login" {
-	if info.FullMethod != "/node.NodeService/CreateNode" {
+		if info.FullMethod != "/node.NodeService/CreateNode" {
 
-		err := grpcAuthorize(ctx)
-		if err != nil {
-			return nil, err
+			err := grpcAuthorize(ctx)
+			if err != nil {
+				return nil, err
+			}
 		}
 	}
-	}
-
 
 	// Calls the handler
 	h, err := handler(ctx, req)
@@ -40,120 +38,129 @@ func AuthServerUnaryInterceptor(ctx context.Context,
 	return h, err
 }
 func AuthServerStreamInterceptor(
-		srv interface{},
-		stream grpc.ServerStream,
-		info *grpc.StreamServerInfo,
-		handler grpc.StreamHandler,
-	) error {
-		if info.FullMethod == "/node.NodeService/GetPeers" {
-			if err := grpcAuthorize(stream.Context()); err != nil {
-				return err
-			}
+	srv interface{},
+	stream grpc.ServerStream,
+	info *grpc.StreamServerInfo,
+	handler grpc.StreamHandler,
+) error {
+	if info.FullMethod == "/node.NodeService/GetPeers" {
+		if err := grpcAuthorize(stream.Context()); err != nil {
+			return err
 		}
+	}
 
-
-		// Calls the handler
-		return handler(srv, stream)
+	// Calls the handler
+	return handler(srv, stream)
 }
 
 func grpcAuthorize(ctx context.Context) error {
 
+	md, ok := metadata.FromIncomingContext(ctx)
 
-		md, ok := metadata.FromIncomingContext(ctx)
-
-		if !ok {
-			return status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed")
-		}
-
-		authHeader, ok := md["authorization"]
-		if !ok {
-			return status.Errorf(codes.Unauthenticated, "Authorization token is not supplied")
-		}
-
-		authToken := authHeader[0]
+	if !ok {
+		return status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed")
+	}
 
-		mac, network, err := functions.VerifyToken(authToken)
+	authHeader, ok := md["authorization"]
+	if !ok {
+		return status.Errorf(codes.Unauthenticated, "Authorization token is not supplied")
+	}
 
-		if err  != nil { return err }
+	authToken := authHeader[0]
 
-                networkexists, err := functions.NetworkExists(network)
+	mac, network, err := functions.VerifyToken(authToken)
+	if err != nil {
+		return err
+	}
 
-		if err != nil {
-			return status.Errorf(codes.Unauthenticated, "Unauthorized. Network does not exist: " + network)
+	networkexists, err := functions.NetworkExists(network)
 
+	if err != nil {
+		return status.Errorf(codes.Unauthenticated, "Unauthorized. Network does not exist: "+network)
+	}
+	emptynode := models.Node{}
+	node, err := functions.GetNodeByMacAddress(network, mac)
+	if database.IsEmptyRecord(err) {
+		if node, err = functions.GetDeletedNodeByMacAddress(network, mac); err == nil {
+			if functions.RemoveDeletedNode(node.ID) {
+				return status.Errorf(codes.Unauthenticated, models.NODE_DELETE)
+			}
+			return status.Errorf(codes.Unauthenticated, "Node does not exist.")
 		}
-		emptynode := models.Node{}
-		node, err := functions.GetNodeByMacAddress(network, mac)
-		if err != nil || node == emptynode {
-                        return status.Errorf(codes.Unauthenticated, "Node does not exist.")
-		}
-
-                //check that the request is for a valid network
-                //if (networkCheck && !networkexists) || err != nil {
-                if (!networkexists) {
-
-			return status.Errorf(codes.Unauthenticated, "Network does not exist.")
+		return status.Errorf(codes.Unauthenticated, "Empty record")
+	}
+	if err != nil || node.MacAddress == emptynode.MacAddress {
+		return status.Errorf(codes.Unauthenticated, "Node does not exist.")
+	}
 
-                } else {
-                        return nil
-                }
+	if !networkexists {
+		return status.Errorf(codes.Unauthenticated, "Network does not exist.")
+	}
+	return nil
 }
 
-
 //Node authenticates using its password and retrieves a JWT for authorization.
-func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.LoginRequest) (*nodepb.LoginResponse, error) {
+func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 
 	//out := new(LoginResponse)
-	macaddress := req.GetMacaddress()
-	network := req.GetNetwork()
-	password := req.GetPassword()
+	var reqNode models.Node
+	if err := json.Unmarshal([]byte(req.Data), &reqNode); err != nil {
+		return nil, err
+	}
+
+	macaddress := reqNode.MacAddress
+	network := reqNode.Network
+	password := reqNode.Password
 
 	var result models.NodeAuth
 
 	err := errors.New("Generic server error.")
 
-
-        if macaddress == "" {
+	if macaddress == "" {
 		//TODO: Set Error  response
 		err = errors.New("Missing Mac Address.")
 		return nil, err
-        } else if password == "" {
-                err = errors.New("Missing Password.")
-                return nil, err
-        } else {
-            //Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
-            collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-            ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	    var err = collection.FindOne(ctx, bson.M{ "macaddress": macaddress, "network": network}).Decode(&result)
-
-            defer cancel()
-
-            if err != nil {
-                return nil, err
-            }
-
-           //compare password from request to stored password in database
-           //might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
-           //TODO: Consider a way of hashing the password client side before sending, or using certificates
-           err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(password))
-	   if err != nil && result.Password != password {
-			return nil, err
-           } else {
-                //Create a new JWT for the node
-                tokenString, err := functions.CreateJWT(macaddress, result.Network)
-
+	} else if password == "" {
+		err = errors.New("Missing Password.")
+		return nil, err
+	} else {
+		//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
+		collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 		if err != nil {
 			return nil, err
 		}
-                if tokenString == "" {
-		    err = errors.New("Something went wrong. Could not retrieve token.")
-                    return nil, err
-                }
+		for _, value := range collection {
+			if err = json.Unmarshal([]byte(value), &result); err != nil {
+				continue // finish going through nodes
+			}
+			if result.MacAddress == macaddress && result.Network == network {
+				break
+			}
+		}
+
+		//compare password from request to stored password in database
+		//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
+		//TODO: Consider a way of hashing the password client side before sending, or using certificates
+		err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(password))
+		if err != nil && result.Password != password {
+			return nil, err
+		} else {
+			//Create a new JWT for the node
+			tokenString, err := functions.CreateJWT(macaddress, result.Network)
+
+			if err != nil {
+				return nil, err
+			}
+			if tokenString == "" {
+				err = errors.New("Something went wrong. Could not retrieve token.")
+				return nil, err
+			}
 
-		response := &nodepb.LoginResponse{
-				Accesstoken: tokenString,
+			response := &nodepb.Object{
+				Data: tokenString,
+				Type: nodepb.ACCESS_TOKEN,
 			}
-		return response, nil
-        }
-    }
+			return response, nil
+		}
+	}
 }

+ 175 - 429
controllers/common.go

@@ -1,365 +1,190 @@
 package controller
 
 import (
-	"context"
-	"fmt"
-	"log"
+	"encoding/json"
+	"strconv"
+	"strings"
 	"time"
 
-	"github.com/go-playground/validator/v10"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/serverctl"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo/options"
 	"golang.org/x/crypto/bcrypt"
 )
 
-func GetPeersList(networkName string) ([]models.PeersResponse, error) {
-
-	var peers []models.PeersResponse
-
-	//Connection mongoDB with mongoconn class
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	//Get all nodes in the relevant network which are NOT in pending state
-	filter := bson.M{"network": networkName, "ispending": false}
-	cur, err := collection.Find(ctx, filter)
+func GetPeersList(networkName string) ([]models.Node, error) {
 
+	var peers []models.Node
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
-		return peers, err
+		if database.IsEmptyRecord(err) {
+			return peers, nil
+		}
+		functions.PrintUserLog("", err.Error(), 2)
+		return nil, err
 	}
-
-	// Close the cursor once finished and cancel if it takes too long
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
-
-		var peer models.PeersResponse
-		err := cur.Decode(&peer)
+	udppeers, errN := database.GetPeers(networkName)
+	if errN != nil {
+		functions.PrintUserLog("", errN.Error(), 2)
+	}
+	for _, value := range collection {
+		var node models.Node
+		var peer models.Node
+		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
-			log.Fatal(err)
+			functions.PrintUserLog("", err.Error(), 2)
+			continue
+		}
+		if node.IsEgressGateway == "yes" { // handle egress stuff
+			peer.EgressGatewayRanges = node.EgressGatewayRanges
+			peer.IsEgressGateway = node.IsEgressGateway
+		}
+		if node.Network == networkName && node.IsPending != "yes" {
+			peer.PublicKey = node.PublicKey
+			peer.Endpoint = node.Endpoint
+			peer.LocalAddress = node.LocalAddress
+			peer.ListenPort = node.ListenPort
+			peer.AllowedIPs = node.AllowedIPs
+			peer.Address = node.Address
+			peer.Address6 = node.Address6
+			if node.UDPHolePunch == "yes" && errN == nil && functions.CheckEndpoint(udppeers[node.PublicKey]) {
+				endpointstring := udppeers[node.PublicKey]
+				endpointarr := strings.Split(endpointstring, ":")
+				if len(endpointarr) == 2 {
+					port, err := strconv.Atoi(endpointarr[1])
+					if err == nil {
+						peer.Endpoint = endpointarr[0]
+						peer.ListenPort = int32(port)
+					}
+				}
+			}
+			functions.PrintUserLog(models.NODE_SERVER_NAME, "adding to peer list: "+peer.MacAddress+" "+peer.Endpoint, 3)
+			peers = append(peers, peer)
 		}
-
-		// add the node to our node array
-		//maybe better to just return this? But then that's just GetNodes...
-		peers = append(peers, peer)
 	}
-
-	//Uh oh, fatal error! This needs some better error handling
-	//TODO: needs appropriate error handling so the server doesnt shut down.
-	if err := cur.Err(); err != nil {
-		log.Fatal(err)
+	if err != nil {
+		return peers, err
 	}
 
 	return peers, err
 }
 
+func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersResponse, error) {
 
-func GetExtPeersList(networkName string, macaddress string) ([]models.ExtPeersResponse, error) {
-
-        var peers []models.ExtPeersResponse
-
-        //Connection mongoDB with mongoconn class
-        collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        //Get all nodes in the relevant network which are NOT in pending state
-	filter := bson.M{"network": networkName, "ingressgatewayid": macaddress}
-        cur, err := collection.Find(ctx, filter)
-
-        if err != nil {
-                return peers, err
-        }
-
-        // Close the cursor once finished and cancel if it takes too long
-        defer cancel()
-
-        for cur.Next(context.TODO()) {
-
-                var peer models.ExtPeersResponse
-                err := cur.Decode(&peer)
-                if err != nil {
-                        log.Fatal(err)
-                }
-
-                // add the node to our node array
-                //maybe better to just return this? But then that's just GetNodes...
-                peers = append(peers, peer)
-        }
-
-        //Uh oh, fatal error! This needs some better error handling
-        //TODO: needs appropriate error handling so the server doesnt shut down.
-        if err := cur.Err(); err != nil {
-                log.Fatal(err)
-        }
-
-        return peers, err
-}
-
-
-func ValidateNodeCreate(networkName string, node models.Node) error {
-	v := validator.New()
-	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
-		var isFieldUnique bool = functions.IsFieldUnique(networkName, "macaddress", node.MacAddress)
-		return isFieldUnique
-	})
-	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-		_, err := node.GetNetwork()
-		return err == nil
-	})
-        _ = v.RegisterValidation("in_charset", func(fl validator.FieldLevel) bool {
-                isgood := functions.NameInNodeCharSet(node.Name)
-                return isgood
-        })
-	err := v.Struct(node)
+	var peers []models.ExtPeersResponse
+	records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
 
 	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
-		}
+		return peers, err
 	}
-	return err
-}
 
-func ValidateNodeUpdate(networkName string, node models.NodeUpdate) error {
-	v := validator.New()
-	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-		_, err := node.GetNetwork()
-		return err == nil
-	})
-        _ = v.RegisterValidation("in_charset", func(fl validator.FieldLevel) bool {
-                isgood := functions.NameInNodeCharSet(node.Name)
-                return isgood
-        })
-	err := v.Struct(node)
-	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+	for _, value := range records {
+		var peer models.ExtPeersResponse
+		var extClient models.ExtClient
+		err = json.Unmarshal([]byte(value), &peer)
+		if err != nil {
+			functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal peer", 2)
+			continue
+		}
+		err = json.Unmarshal([]byte(value), &extClient)
+		if err != nil {
+			functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal ext client", 2)
+			continue
+		}
+		if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
+			peers = append(peers, peer)
 		}
 	}
-	return err
+	return peers, err
 }
 
-func UpdateNode(nodechange models.NodeUpdate, node models.Node) (models.Node, error) {
-	//Question: Is there a better way  of doing  this than a bunch of "if" statements? probably...
-	//Eventually, lets have a better way to check if any of the fields are filled out...
-	queryMac := node.MacAddress
-	queryNetwork := node.Network
-	notifynetwork := false
-
-	if nodechange.Address != "" {
-		node.Address = nodechange.Address
-		notifynetwork = true
-	}
-	if nodechange.Address6 != "" {
-		node.Address6 = nodechange.Address6
-		notifynetwork = true
-	}
-	if nodechange.Name != "" {
-		node.Name = nodechange.Name
-	}
-	if nodechange.LocalAddress != "" {
-		node.LocalAddress = nodechange.LocalAddress
-	}
-	if nodechange.ListenPort != 0 {
-		node.ListenPort = nodechange.ListenPort
-	}
-	if nodechange.ExpirationDateTime != 0 {
-		node.ExpirationDateTime = nodechange.ExpirationDateTime
-	}
-	if nodechange.PostDown != "" {
-		node.PostDown = nodechange.PostDown
-	}
-	if nodechange.Interface != "" {
-		node.Interface = nodechange.Interface
-	}
-	if nodechange.PostUp != "" {
-		node.PostUp = nodechange.PostUp
-	}
-	if nodechange.AccessKey != "" {
-		node.AccessKey = nodechange.AccessKey
-	}
-	if nodechange.Endpoint != "" {
-		node.Endpoint = nodechange.Endpoint
-		notifynetwork = true
-	}
-	if nodechange.SaveConfig != nil {
-		node.SaveConfig = nodechange.SaveConfig
-	}
-	if nodechange.PersistentKeepalive != 0 {
-		node.PersistentKeepalive = nodechange.PersistentKeepalive
-	}
-	if nodechange.Password != "" {
-		err := bcrypt.CompareHashAndPassword([]byte(nodechange.Password), []byte(node.Password))
-		if err != nil && nodechange.Password != node.Password {
-			hash, err := bcrypt.GenerateFromPassword([]byte(nodechange.Password), 5)
-			if err != nil {
-				return node, err
-			}
-			nodechange.Password = string(hash)
-			node.Password = nodechange.Password
+/**
+ * If being deleted by server, create a record in the DELETED_NODES_TABLE for the client to find
+ * If being deleted by the client, delete completely
+ */
+func DeleteNode(key string, exterminate bool) error {
+	var err error
+	if !exterminate {
+		args := strings.Split(key, "###")
+		node, err := GetNode(args[0], args[1])
+		if err != nil {
+			return err
+		}
+		node.Action = models.NODE_DELETE
+		nodedata, err := json.Marshal(&node)
+		if err != nil {
+			return err
+		}
+		err = database.Insert(key, string(nodedata), database.DELETED_NODES_TABLE_NAME)
+		if err != nil {
+			return err
+		}
+	} else {
+		if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
+			functions.PrintUserLog("", err.Error(), 2)
 		}
 	}
-	if nodechange.MacAddress != "" {
-		node.MacAddress = nodechange.MacAddress
-	}
-	if nodechange.PublicKey != "" {
-		node.PublicKey = nodechange.PublicKey
-		node.KeyUpdateTimeStamp = time.Now().Unix()
-		notifynetwork = true
-	}
-
-	//collection := mongoconn.ConnectDB()
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"macaddress": queryMac, "network": queryNetwork}
-
-	node.SetLastModified()
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"address", node.Address},
-			{"address6", node.Address6},
-			{"name", node.Name},
-			{"password", node.Password},
-			{"listenport", node.ListenPort},
-			{"publickey", node.PublicKey},
-			{"keyupdatetimestamp", node.KeyUpdateTimeStamp},
-			{"expdatetime", node.ExpirationDateTime},
-			{"endpoint", node.Endpoint},
-			{"postup", node.PostUp},
-			{"postdown", node.PostDown},
-			{"macaddress", node.MacAddress},
-			{"localaddress", node.LocalAddress},
-			{"persistentkeepalive", node.PersistentKeepalive},
-			{"saveconfig", node.SaveConfig},
-			{"accesskey", node.AccessKey},
-			{"interface", node.Interface},
-			{"lastmodified", node.LastModified},
-		}},
-	}
-	var nodeupdate models.Node
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	if errN != nil {
-		return nodeupdate, errN
-	}
-
-	if nodechange.MacAddress != "" {
-		queryMac = nodechange.MacAddress
-	}
-	returnnode, errN := GetNode(queryMac, queryNetwork)
-
-	defer cancel()
-
-	if notifynetwork {
-		errN = SetNetworkNodesLastModified(queryNetwork)
-	}
-	if servercfg.IsDNSMode() {
-		errN = SetDNS()
-	}
-
-	return returnnode, errN
-}
-
-func DeleteNode(macaddress string, network string) (bool, error) {
-
-	deleted := false
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	filter := bson.M{"macaddress": macaddress, "network": network}
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	result, err := collection.DeleteOne(ctx, filter)
-
-	deletecount := result.DeletedCount
-
-	if deletecount > 0 {
-		deleted = true
+	if err := database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
+		return err
 	}
-
-	defer cancel()
-
-	err = SetNetworkNodesLastModified(network)
-	fmt.Println("Deleted node " + macaddress + " from network " + network)
 	if servercfg.IsDNSMode() {
 		err = SetDNS()
 	}
-
-	return deleted, err
+	return err
 }
 
 func DeleteIntClient(clientid string) (bool, error) {
 
-        deleted := false
-
-        collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-
-        filter := bson.M{"clientid": clientid}
-
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        result, err := collection.DeleteOne(ctx, filter)
-
-        deletecount := result.DeletedCount
-
-        if deletecount > 0 {
-                deleted = true
-        }
-
-        defer cancel()
-
-	err = serverctl.ReconfigureServerWireGuard()
+	err := database.DeleteRecord(database.INT_CLIENTS_TABLE_NAME, clientid)
+	if err != nil {
+		return false, err
+	}
 
-        return deleted, err
+	return true, nil
 }
 
 func GetNode(macaddress string, network string) (models.Node, error) {
 
 	var node models.Node
 
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"macaddress": macaddress, "network": network}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&node)
-
-	defer cancel()
+	key, err := functions.GetRecordKey(macaddress, network)
+	if err != nil {
+		return node, err
+	}
+	data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
+	if err != nil {
+		if data == "" {
+			data, err = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)
+			err = json.Unmarshal([]byte(data), &node)
+		}
+		return node, err
+	}
+	if err = json.Unmarshal([]byte(data), &node); err != nil {
+		return node, err
+	}
 
 	return node, err
 }
 
 func GetIntClient(clientid string) (models.IntClient, error) {
 
-        var client models.IntClient
-
-        collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        filter := bson.M{"clientid": clientid}
-        err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&clientid)
+	var client models.IntClient
 
-        defer cancel()
-
-        return client, err
+	value, err := database.FetchRecord(database.INT_CLIENTS_TABLE_NAME, clientid)
+	if err != nil {
+		return client, err
+	}
+	if err = json.Unmarshal([]byte(value), &client); err != nil {
+		return models.IntClient{}, err
+	}
+	return client, nil
 }
 
 func CreateNode(node models.Node, networkName string) (models.Node, error) {
 
-	//encrypt that password so we never see it again
+	//encrypt that password so we never see it
 	hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
 
 	if err != nil {
@@ -369,63 +194,49 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) {
 	node.Password = string(hash)
 
 	node.Network = networkName
+	if node.Name == models.NODE_SERVER_NAME {
+		if node.CheckIsServer() {
+			node.IsServer = "yes"
+		}
+	}
 
-	//node.SetDefaults()
-	//Umm, why am I doing this again?
-	//TODO: Why am I using a local function instead of the struct function? I really dont know.
-	//I think I thought it didn't work but uhhh...idk
 	node.SetDefaults()
-
-	//Another DB call here...Inefficient
-	//Anyways, this scrolls through all the IP Addresses in the network range and checks against nodes
-	//until one is open and then returns it
 	node.Address, err = functions.UniqueAddress(networkName)
 	if err != nil {
 		return node, err
 	}
-
 	node.Address6, err = functions.UniqueAddress6(networkName)
-
 	if err != nil {
 		return node, err
 	}
-
-	//IDK why these aren't a part of "set defaults. Pretty dumb.
-	//TODO: This is dumb. Consolidate and fix.
-	node.SetLastModified()
-	node.SetDefaultName()
-	node.SetLastCheckIn()
-	node.SetLastPeerUpdate()
-	node.KeyUpdateTimeStamp = time.Now().Unix()
-
 	//Create a JWT for the node
 	tokenString, _ := functions.CreateJWT(node.MacAddress, networkName)
-
 	if tokenString == "" {
 		//returnErrorResponse(w, r, errorResponse)
 		return node, err
 	}
-
-	// connect db
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// insert our node to the node db.
-	result, err := collection.InsertOne(ctx, node)
-	_ = result
-
-	defer cancel()
-
+	if servercfg.IsDNSMode() {
+		node.DNSOn = "yes"
+	}
+	err = node.Validate(false)
 	if err != nil {
 		return node, err
 	}
-	//return response for if node  is pending
-	if !node.IsPending {
-
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return node, err
+	}
+	nodebytes, err := json.Marshal(&node)
+	if err != nil {
+		return node, err
+	}
+	err = database.Insert(key, string(nodebytes), database.NODES_TABLE_NAME)
+	if err != nil {
+		return node, err
+	}
+	if node.IsPending != "yes" {
 		functions.DecrimentKey(node.Network, node.AccessKey)
-
 	}
-
 	SetNetworkNodesLastModified(node.Network)
 	if servercfg.IsDNSMode() {
 		err = SetDNS()
@@ -433,90 +244,34 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) {
 	return node, err
 }
 
-func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse, error) {
-
-	var response models.CheckInResponse
-
-	parentnetwork, err := functions.GetParentNetwork(networkName)
-	if err != nil {
-		err = fmt.Errorf("%w; Couldnt retrieve Network "+networkName+": ", err)
-		return response, err
-	}
-
-	parentnode, err := functions.GetNodeByMacAddress(networkName, node.MacAddress)
-	if err != nil {
-		err = fmt.Errorf("%w; Couldnt Get Node "+node.MacAddress, err)
-		return response, err
-	}
-	if parentnode.IsPending {
-		err = fmt.Errorf("%w; Node checking in is still pending: "+node.MacAddress, err)
-		response.IsPending = true
-		return response, err
-	}
-
-	networklm := parentnetwork.NetworkLastModified
-	peerslm := parentnetwork.NodesLastModified
-	gkeyupdate := parentnetwork.KeyUpdateTimeStamp
-	nkeyupdate := parentnode.KeyUpdateTimeStamp
-	peerlistlm := parentnode.LastPeerUpdate
-	parentnodelm := parentnode.LastModified
-	parentnodelastcheckin := parentnode.LastCheckIn
-
-	if parentnodelastcheckin < parentnodelm {
-		response.NeedConfigUpdate = true
-	}
-
-	if parentnodelm < networklm {
-		response.NeedConfigUpdate = true
-	}
-	if peerlistlm < peerslm {
-		response.NeedPeerUpdate = true
-	}
-	if nkeyupdate < gkeyupdate {
-		response.NeedKeyUpdate = true
-	}
-	if time.Now().Unix() > parentnode.ExpirationDateTime {
-		response.NeedDelete = true
-		_, err = DeleteNode(node.MacAddress, networkName)
-	} else {
-		err = TimestampNode(parentnode, true, false, false)
-
-		if err != nil {
-			err = fmt.Errorf("%w; Couldnt Timestamp Node: ", err)
-			return response, err
+func SetNetworkServerPeers(networkName string) {
+	if currentPeersList, err := serverctl.GetPeers(networkName); err == nil {
+		if database.SetPeers(currentPeersList, networkName) {
+			functions.PrintUserLog(models.NODE_SERVER_NAME, "set new peers on network "+networkName, 1)
 		}
+	} else {
+		functions.PrintUserLog(models.NODE_SERVER_NAME, "could not set peers on network "+networkName, 1)
+		functions.PrintUserLog(models.NODE_SERVER_NAME, err.Error(), 1)
 	}
-	response.Success = true
-
-	return response, err
 }
 
 func SetNetworkNodesLastModified(networkName string) error {
 
 	timestamp := time.Now().Unix()
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"netid": networkName}
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"nodeslastmodified", timestamp},
-		}},
+	network, err := functions.GetParentNetwork(networkName)
+	if err != nil {
+		return err
 	}
-
-	result := collection.FindOneAndUpdate(ctx, filter, update)
-
-	defer cancel()
-
-	if result.Err() != nil {
-		return result.Err()
+	network.NodesLastModified = timestamp
+	data, err := json.Marshal(&network)
+	if err != nil {
+		return err
+	}
+	err = database.Insert(networkName, string(data), database.NETWORKS_TABLE_NAME)
+	if err != nil {
+		return err
 	}
-
 	return nil
 }
 
@@ -531,25 +286,16 @@ func TimestampNode(node models.Node, updatecheckin bool, updatepeers bool, updat
 		node.SetLastPeerUpdate()
 	}
 
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"macaddress": node.MacAddress, "network": node.Network}
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"lastmodified", node.LastModified},
-			{"lastpeerupdate", node.LastPeerUpdate},
-			{"lastcheckin", node.LastCheckIn},
-		}},
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return err
+	}
+	value, err := json.Marshal(&node)
+	if err != nil {
+		return err
 	}
 
-	var nodeupdate models.Node
-	err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
+	err = database.Insert(key, string(value), database.NODES_TABLE_NAME)
 
 	return err
 }

+ 11 - 19
controllers/common_test.go

@@ -1,14 +1,13 @@
 package controller
 
 import (
-	"context"
+	"encoding/json"
 	"testing"
 	"time"
 
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/stretchr/testify/assert"
-	"go.mongodb.org/mongo-driver/bson"
 )
 
 type NodeValidationTC struct {
@@ -51,14 +50,12 @@ func TestDeleteNode(t *testing.T) {
 	createNet()
 	node := createTestNode(t)
 	t.Run("NodeExists", func(t *testing.T) {
-		deleted, err := DeleteNode(node.MacAddress, node.Network)
+		err := DeleteNode(node.MacAddress, node.Network)
 		assert.Nil(t, err)
-		assert.True(t, deleted)
 	})
 	t.Run("NonExistantNode", func(t *testing.T) {
-		deleted, err := DeleteNode(node.MacAddress, node.Network)
+		err := DeleteNode(node.MacAddress, node.Network)
 		assert.Nil(t, err)
-		assert.False(t, deleted)
 	})
 }
 func TestGetNode(t *testing.T) {
@@ -89,7 +86,7 @@ func TestGetNode(t *testing.T) {
 		assert.Equal(t, "mongo: no documents in result", err.Error())
 	})
 	t.Run("NoNode", func(t *testing.T) {
-		_, _ = DeleteNode("01:02:03:04:05:06", "skynet")
+		_ = DeleteNode("01:02:03:04:05:06", "skynet")
 		response, err := GetNode(node.MacAddress, node.Network)
 		assert.NotNil(t, err)
 		assert.Equal(t, models.Node{}, response)
@@ -110,7 +107,7 @@ func TestGetPeerList(t *testing.T) {
 		t.Log(peers)
 	})
 	t.Run("NoNodes", func(t *testing.T) {
-		_, _ = DeleteNode("01:02:03:04:05:06", "skynet")
+		_ = DeleteNode("01:02:03:04:05:06", "skynet")
 		peers, err := GetPeersList("skynet")
 		assert.Nil(t, err)
 		assert.Equal(t, []models.PeersResponse(nil), peers)
@@ -178,17 +175,12 @@ func TestNodeCheckIn(t *testing.T) {
 		newtime := time.Now().Add(time.Hour * 24).Unix()
 		t.Log(newtime, time.Now().Unix())
 		//this is cheating; but can't find away to update timestamp through existing api
-		collection := mongoconn.Client.Database("netmaker").Collection("networks")
-		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-		filter := bson.M{"netid": "skynet"}
-		update := bson.D{
-			{"$set", bson.D{
-				{"keyupdatetimestamp", newtime},
-			}},
-		}
-		defer cancel()
-		err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
+
+		record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, "skynet")
+		assert.Nil(t, err)
+		err = json.Unmarshal([]byte(record), &network)
 		assert.Nil(t, err)
+		network.KeyUpdateTimeStamp = newtime
 		response, err := NodeCheckIn(node, "skynet")
 		assert.Nil(t, err)
 		assert.Equal(t, true, response.Success)

+ 2 - 8
controllers/config/environments/dev.yaml

@@ -2,16 +2,10 @@ server:
   host: "localhost"
   apiport: "8081"
   grpcport: "50051"
-  masterkey: "secretkey"
+  masterkey: ""
   allowedorigin: "*"
   restbackend: true            
   agentbackend: true
   defaultnetname: "default"
   defaultnetrange: "10.10.10.0/24"
-  createdefault: true
-mongoconn:
-  user: "mongoadmin"
-  pass: "mongopass"
-  host: "localhost"
-  port: "27017"
-  opts: '/?authSource=admin'
+  createdefault: true

+ 44 - 48
controllers/controller.go

@@ -1,63 +1,59 @@
 package controller
 
 import (
-    "github.com/gravitl/netmaker/mongoconn"
-    "github.com/gravitl/netmaker/servercfg"
-    "os/signal"
-    "os"
-    "log"
-    "context"
-    "net/http"
-    "github.com/gorilla/mux"
-    "github.com/gorilla/handlers"
-    "sync"
+	"context"
+	"log"
+	"net/http"
+	"os"
+	"os/signal"
+	"sync"
+	"github.com/gorilla/handlers"
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/servercfg"
 )
 
-
 func HandleRESTRequests(wg *sync.WaitGroup) {
-    defer wg.Done()
-
-    r := mux.NewRouter()
-
-    // Currently allowed dev origin is all. Should change in prod
-    // should consider analyzing the allowed methods further
-    headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization"})
-    originsOk := handlers.AllowedOrigins([]string{servercfg.GetAllowedOrigin()})
-    methodsOk := handlers.AllowedMethods([]string{"GET", "PUT", "POST", "DELETE"})
-
-    nodeHandlers(r)
-    userHandlers(r)
-    networkHandlers(r)
-    dnsHandlers(r)
-    fileHandlers(r)
-    serverHandlers(r)
-    extClientHandlers(r)
-    intClientHandlers(r)
-
-		port := servercfg.GetAPIPort()
-
-		srv := &http.Server{Addr: ":" + port, Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r)}
-		go func(){
+	defer wg.Done()
+
+	r := mux.NewRouter()
+
+	// Currently allowed dev origin is all. Should change in prod
+	// should consider analyzing the allowed methods further
+	headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization"})
+	originsOk := handlers.AllowedOrigins([]string{servercfg.GetAllowedOrigin()})
+	methodsOk := handlers.AllowedMethods([]string{"GET", "PUT", "POST", "DELETE"})
+
+	nodeHandlers(r)
+	userHandlers(r)
+	networkHandlers(r)
+	dnsHandlers(r)
+	fileHandlers(r)
+	serverHandlers(r)
+	extClientHandlers(r)
+	
+	port := servercfg.GetAPIPort()
+
+	srv := &http.Server{Addr: ":" + port, Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r)}
+	go func() {
 		err := srv.ListenAndServe()
 		if err != nil {
 			log.Println(err)
 		}
-		}()
+	}()
 
-		log.Println("REST Server succesfully started on port " + port + " (REST)")
-		c := make(chan os.Signal)
+	log.Println("REST Server succesfully started on port " + port + " (REST)")
+	c := make(chan os.Signal)
 
-		// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
-		// Ignore other incoming signals
-		signal.Notify(c, os.Interrupt)
+	// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
+	// Ignore other incoming signals
+	signal.Notify(c, os.Interrupt)
 
-		// Block main routine until a signal is received
-		// As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
-		<-c
+	// Block main routine until a signal is received
+	// As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
+	<-c
 
-		// After receiving CTRL+C Properly stop the server
-		log.Println("Stopping the REST server...")
-		srv.Shutdown(context.TODO())
-                log.Println("REST Server closed.")
-		mongoconn.Client.Disconnect(context.TODO())
+	// After receiving CTRL+C Properly stop the server
+	log.Println("Stopping the REST server...")
+	srv.Shutdown(context.TODO())
+	log.Println("REST Server closed.")
 }

+ 90 - 150
controllers/dnsHttpController.go

@@ -1,33 +1,26 @@
 package controller
 
 import (
-	"context"
 	"encoding/json"
-	"errors"
-	"fmt"
 	"net/http"
-	"time"
-
 	"github.com/go-playground/validator/v10"
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/txn2/txeh"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo/options"
 )
 
 func dnsHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/dns", securityCheck(http.HandlerFunc(getAllDNS))).Methods("GET")
-	r.HandleFunc("/api/dns/adm/{network}/nodes", securityCheck(http.HandlerFunc(getNodeDNS))).Methods("GET")
-	r.HandleFunc("/api/dns/adm/{network}/custom", securityCheck(http.HandlerFunc(getCustomDNS))).Methods("GET")
-	r.HandleFunc("/api/dns/adm/{network}", securityCheck(http.HandlerFunc(getDNS))).Methods("GET")
-	r.HandleFunc("/api/dns/{network}", securityCheck(http.HandlerFunc(createDNS))).Methods("POST")
-	r.HandleFunc("/api/dns/adm/pushdns", securityCheck(http.HandlerFunc(pushDNS))).Methods("POST")
-	r.HandleFunc("/api/dns/{network}/{domain}", securityCheck(http.HandlerFunc(deleteDNS))).Methods("DELETE")
-	r.HandleFunc("/api/dns/{network}/{domain}", securityCheck(http.HandlerFunc(updateDNS))).Methods("PUT")
+	r.HandleFunc("/api/dns", securityCheck(true, http.HandlerFunc(getAllDNS))).Methods("GET")
+	r.HandleFunc("/api/dns/adm/{network}/nodes", securityCheck(false, http.HandlerFunc(getNodeDNS))).Methods("GET")
+	r.HandleFunc("/api/dns/adm/{network}/custom", securityCheck(false, http.HandlerFunc(getCustomDNS))).Methods("GET")
+	r.HandleFunc("/api/dns/adm/{network}", securityCheck(false, http.HandlerFunc(getDNS))).Methods("GET")
+	r.HandleFunc("/api/dns/{network}", securityCheck(false, http.HandlerFunc(createDNS))).Methods("POST")
+	r.HandleFunc("/api/dns/adm/pushdns", securityCheck(false, http.HandlerFunc(pushDNS))).Methods("POST")
+	r.HandleFunc("/api/dns/{network}/{domain}", securityCheck(false, http.HandlerFunc(deleteDNS))).Methods("DELETE")
+	r.HandleFunc("/api/dns/{network}/{domain}", securityCheck(false, http.HandlerFunc(updateDNS))).Methods("PUT")
 }
 
 //Gets all nodes associated with network, including pending nodes
@@ -64,7 +57,7 @@ func getAllDNS(w http.ResponseWriter, r *http.Request) {
 
 func GetAllDNS() ([]models.DNSEntry, error) {
 	var dns []models.DNSEntry
-	networks, err := functions.ListNetworks()
+	networks, err := models.GetNetworks()
 	if err != nil {
 		return []models.DNSEntry{}, err
 	}
@@ -82,39 +75,23 @@ func GetNodeDNS(network string) ([]models.DNSEntry, error) {
 
 	var dns []models.DNSEntry
 
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": network}
-
-	cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
-
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
 		return dns, err
 	}
 
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
-
+	for _, value := range collection {
 		var entry models.DNSEntry
-
-		err := cur.Decode(&entry)
-		if err != nil {
-			return dns, err
+		var node models.Node
+		if err = json.Unmarshal([]byte(value), &node); err != nil {
+			continue
+		}
+		if err = json.Unmarshal([]byte(value), &entry); node.Network == network && err == nil {
+			dns = append(dns, entry)
 		}
-
-		// add item our array of nodes
-		dns = append(dns, entry)
-	}
-
-	//TODO: Another fatal error we should take care of.
-	if err := cur.Err(); err != nil {
-		return dns, err
 	}
 
-	return dns, err
+	return dns, nil
 }
 
 //Gets all nodes associated with network, including pending nodes
@@ -140,36 +117,19 @@ func GetCustomDNS(network string) ([]models.DNSEntry, error) {
 
 	var dns []models.DNSEntry
 
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": network}
-
-	cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
-
+	collection, err := database.FetchRecords(database.DNS_TABLE_NAME)
 	if err != nil {
 		return dns, err
 	}
-
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
-
+	for _, value := range collection { // filter for entries based on network
 		var entry models.DNSEntry
-
-		err := cur.Decode(&entry)
-		if err != nil {
-			return dns, err
+		if err := json.Unmarshal([]byte(value), &entry); err != nil {
+			continue
 		}
 
-		// add item our array of nodes
-		dns = append(dns, entry)
-	}
-
-	//TODO: Another fatal error we should take care of.
-	if err := cur.Err(); err != nil {
-		return dns, err
+		if entry.Network == network {
+			dns = append(dns, entry)
+		}
 	}
 
 	return dns, err
@@ -178,7 +138,7 @@ func GetCustomDNS(network string) ([]models.DNSEntry, error) {
 func SetDNS() error {
 	hostfile := txeh.Hosts{}
 	var corefilestring string
-	networks, err := functions.ListNetworks()
+	networks, err := models.GetNetworks()
 	if err != nil {
 		return err
 	}
@@ -186,14 +146,11 @@ func SetDNS() error {
 	for _, net := range networks {
 		corefilestring = corefilestring + net.NetID + " "
 		dns, err := GetDNS(net.NetID)
-		if err != nil {
+		if err != nil && !database.IsEmptyRecord(err) {
 			return err
 		}
 		for _, entry := range dns {
 			hostfile.AddHost(entry.Address, entry.Name+"."+entry.Network)
-			if err != nil {
-				return err
-			}
 		}
 	}
 	if corefilestring == "" {
@@ -249,16 +206,16 @@ func GetDNS(network string) ([]models.DNSEntry, error) {
 
 	var dns []models.DNSEntry
 	dns, err := GetNodeDNS(network)
-	if err != nil {
+	if err != nil && !database.IsEmptyRecord(err) {
 		return dns, err
 	}
 	customdns, err := GetCustomDNS(network)
-	if err != nil {
+	if err != nil && !database.IsEmptyRecord(err) {
 		return dns, err
 	}
 
 	dns = append(dns, customdns...)
-	return dns, err
+	return dns, nil
 }
 
 func createDNS(w http.ResponseWriter, r *http.Request) {
@@ -282,6 +239,11 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	err = SetDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(entry)
 }
@@ -332,7 +294,11 @@ func updateDNS(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
-
+	err = SetDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	json.NewEncoder(w).Encode(entry)
 }
 
@@ -343,109 +309,83 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
 	// get params
 	var params = mux.Vars(r)
 
-	success, err := DeleteDNS(params["domain"], params["network"])
+	err := DeleteDNS(params["domain"], params["network"])
 
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
-	} else if !success {
-		returnErrorResponse(w, r, formatError(errors.New("Delete unsuccessful."), "badrequest"))
+	}
+	entrytext := params["domain"] + "." + params["network"]
+	functions.PrintUserLog(models.NODE_SERVER_NAME, "deleted dns entry: "+entrytext, 1)
+	err = SetDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
-	json.NewEncoder(w).Encode(params["domain"] + " deleted.")
+	json.NewEncoder(w).Encode(entrytext + " deleted.")
 }
 
 func CreateDNS(entry models.DNSEntry) (models.DNSEntry, error) {
 
-	// connect db
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// insert our node to the node db.
-	_, err := collection.InsertOne(ctx, entry)
-
-	defer cancel()
+	data, err := json.Marshal(&entry)
+	if err != nil {
+		return models.DNSEntry{}, err
+	}
+	key, err := functions.GetRecordKey(entry.Name, entry.Network)
+	if err != nil {
+		return models.DNSEntry{}, err
+	}
+	err = database.Insert(key, string(data), database.DNS_TABLE_NAME)
 
 	return entry, err
 }
 
 func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
 	var entry models.DNSEntry
-
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"name": domain, "network": network}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&entry)
-
-	defer cancel()
-
+	key, err := functions.GetRecordKey(domain, network)
+	if err != nil {
+		return entry, err
+	}
+	record, err := database.FetchRecord(database.DNS_TABLE_NAME, key)
+	if err != nil {
+		return entry, err
+	}
+	err = json.Unmarshal([]byte(record), &entry)
 	return entry, err
 }
 
 func UpdateDNS(dnschange models.DNSEntry, entry models.DNSEntry) (models.DNSEntry, error) {
 
-	queryDNS := entry.Name
-
+	key, err := functions.GetRecordKey(entry.Name, entry.Network)
+	if err != nil {
+		return entry, err
+	}
 	if dnschange.Name != "" {
 		entry.Name = dnschange.Name
 	}
 	if dnschange.Address != "" {
 		entry.Address = dnschange.Address
 	}
-	//collection := mongoconn.ConnectDB()
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"name": queryDNS}
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"name", entry.Name},
-			{"address", entry.Address},
-		}},
-	}
-	var dnsupdate models.DNSEntry
+	newkey, err := functions.GetRecordKey(entry.Name, entry.Network)
 
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&dnsupdate)
-	if errN != nil {
-		fmt.Println("Could not update: ")
-		fmt.Println(errN)
-	} else {
-		fmt.Println("DNS Entry updated successfully.")
+	err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
+	if err != nil {
+		return entry, err
 	}
 
-	defer cancel()
+	data, err := json.Marshal(&entry)
+	err = database.Insert(newkey, string(data), database.DNS_TABLE_NAME)
+	return entry, err
 
-	return dnsupdate, errN
 }
 
-func DeleteDNS(domain string, network string) (bool, error) {
-	fmt.Println("delete dns entry ", domain, network)
-	deleted := false
-
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-
-	filter := bson.M{"name": domain, "network": network}
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	result, err := collection.DeleteOne(ctx, filter)
-
-	deletecount := result.DeletedCount
-
-	if deletecount > 0 {
-		deleted = true
+func DeleteDNS(domain string, network string) error {
+	key, err := functions.GetRecordKey(domain, network)
+	if err != nil {
+		return err
 	}
-
-	defer cancel()
-
-	return deleted, err
+	err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
+	return err
 }
 
 func pushDNS(w http.ResponseWriter, r *http.Request) {
@@ -458,15 +398,13 @@ func pushDNS(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"),"pushed DNS updates to nameserver",1)
 	json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
 }
 
 func ValidateDNSCreate(entry models.DNSEntry) error {
 
 	v := validator.New()
-	fmt.Println("Validating DNS: " + entry.Name)
-	fmt.Println("       Address: " + entry.Address)
-	fmt.Println("       Network: " + entry.Network)
 
 	_ = v.RegisterValidation("name_unique", func(fl validator.FieldLevel) bool {
 		num, err := GetDNSEntryNum(entry.Name, entry.Network)
@@ -481,7 +419,7 @@ func ValidateDNSCreate(entry models.DNSEntry) error {
 	err := v.Struct(entry)
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+			functions.PrintUserLog("", e.Error(),1)
 		}
 	}
 	return err
@@ -501,7 +439,9 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
 	})
 	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
 		_, err := functions.GetParentNetwork(change.Network)
-		fmt.Println(err, entry.Network)
+		if err != nil {
+			functions.PrintUserLog("",err.Error(),0)
+		}
 		return err == nil
 	})
 
@@ -523,7 +463,7 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
 
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+			functions.PrintUserLog("", e.Error(),1)
 		}
 	}
 	return err

+ 4 - 6
controllers/dnsHttpController_test.go

@@ -54,21 +54,19 @@ func TestUpdateDNS(t *testing.T) {
 }
 func TestDeleteDNS(t *testing.T) {
 	t.Run("EntryExists", func(t *testing.T) {
-		success, err := DeleteDNS("myhost", "skynet")
+		err := DeleteDNS("myhost", "skynet")
 		assert.Nil(t, err)
-		assert.True(t, success)
 	})
 	t.Run("NoEntry", func(t *testing.T) {
-		success, err := DeleteDNS("myhost", "skynet")
+		err := DeleteDNS("myhost", "skynet")
 		assert.Nil(t, err)
-		assert.False(t, success)
 	})
 
 }
 
 func TestValidateDNSUpdate(t *testing.T) {
 	entry := models.DNSEntry{"10.0.0.2", "myhost", "skynet"}
-	_, _ = DeleteDNS("mynode", "skynet")
+	_ = DeleteDNS("mynode", "skynet")
 	t.Run("BadNetwork", func(t *testing.T) {
 		change := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
 		err := ValidateDNSUpdate(change, entry)
@@ -129,7 +127,7 @@ func TestValidateDNSUpdate(t *testing.T) {
 
 }
 func TestValidateDNSCreate(t *testing.T) {
-	_, _ = DeleteDNS("mynode", "skynet")
+	_ = DeleteDNS("mynode", "skynet")
 	t.Run("NoNetwork", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
 		err := ValidateDNSCreate(entry)

+ 172 - 225
controllers/extClientHttpController.go

@@ -1,73 +1,31 @@
 package controller
 
 import (
-	"context"
 	"encoding/json"
-	"io"
 	"errors"
 	"fmt"
-        "math/rand"
-
-	// "fmt"
+	"io"
+	"math/rand"
 	"net/http"
-	"time"
 	"strconv"
+	"time"
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo/options"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"github.com/skip2/go-qrcode"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
 func extClientHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/extclients", securityCheck(http.HandlerFunc(getAllExtClients))).Methods("GET")
-	r.HandleFunc("/api/extclients/{network}", securityCheck(http.HandlerFunc(getNetworkExtClients))).Methods("GET")
-	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(http.HandlerFunc(getExtClient))).Methods("GET")
-	r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", securityCheck(http.HandlerFunc(getExtClientConf))).Methods("GET")
-	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(http.HandlerFunc(updateExtClient))).Methods("PUT")
-	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(http.HandlerFunc(deleteExtClient))).Methods("DELETE")
-	r.HandleFunc("/api/extclients/{network}/{macaddress}", securityCheck(http.HandlerFunc(createExtClient))).Methods("POST")
-}
-
-// TODO: Implement Validation
-func ValidateExtClientCreate(networkName string, extclient models.ExtClient) error {
-	// 	v := validator.New()
-	// 	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
-	// 		var isFieldUnique bool = functions.IsFieldUnique(networkName, "macaddress", extclient.MacAddress)
-	// 		return isFieldUnique
-	// 	})
-	// 	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-	// 		_, err := extclient.GetNetwork()
-	// 		return err == nil
-	// 	})
-	// 	err := v.Struct(extclient)
-
-	// 	if err != nil {
-	// 		for _, e := range err.(validator.ValidationErrors) {
-	// 			fmt.Println(e)
-	// 		}
-	// 	}
-	return nil
-}
-
-// TODO: Implement Validation
-func ValidateExtClientUpdate(networkName string, extclient models.ExtClient) error {
-	// v := validator.New()
-	// _ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-	// 	_, err := extclient.GetNetwork()
-	// 	return err == nil
-	// })
-	// err := v.Struct(extclient)
-	// if err != nil {
-	// 	for _, e := range err.(validator.ValidationErrors) {
-	// 		fmt.Println(e)
-	// 	}
-	// }
-	return nil
+	r.HandleFunc("/api/extclients", securityCheck(false, http.HandlerFunc(getAllExtClients))).Methods("GET")
+	r.HandleFunc("/api/extclients/{network}", securityCheck(false, http.HandlerFunc(getNetworkExtClients))).Methods("GET")
+	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(false, http.HandlerFunc(getExtClient))).Methods("GET")
+	r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", securityCheck(false, http.HandlerFunc(getExtClientConf))).Methods("GET")
+	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(false, http.HandlerFunc(updateExtClient))).Methods("PUT")
+	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(false, http.HandlerFunc(deleteExtClient))).Methods("DELETE")
+	r.HandleFunc("/api/extclients/{network}/{macaddress}", securityCheck(false, http.HandlerFunc(createExtClient))).Methods("POST")
 }
 
 func checkIngressExists(network string, macaddress string) bool {
@@ -75,7 +33,7 @@ func checkIngressExists(network string, macaddress string) bool {
 	if err != nil {
 		return false
 	}
-	return node.IsIngressGateway
+	return node.IsIngressGateway == "yes"
 }
 
 //Gets all extclients associated with network, including pending extclients
@@ -98,48 +56,57 @@ func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 
 func GetNetworkExtClients(network string) ([]models.ExtClient, error) {
 	var extclients []models.ExtClient
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"network": network}
-	//Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future
-	cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
+
+	records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
 	if err != nil {
-		return []models.ExtClient{}, err
-	}
-	defer cancel()
-	for cur.Next(context.TODO()) {
-		//Using a different model for the ReturnExtClient (other than regular extclient).
-		//Either we should do this for ALL structs (so Networks and Keys)
-		//OR we should just use the original struct
-		//My preference is to make some new return structs
-		//TODO: Think about this. Not an immediate concern. Just need to get some consistency eventually
+		return extclients, err
+	}
+	for _, value := range records {
 		var extclient models.ExtClient
-		err := cur.Decode(&extclient)
+		err = json.Unmarshal([]byte(value), &extclient)
 		if err != nil {
-			return []models.ExtClient{}, err
+			continue
+		}
+		if extclient.Network == network {
+			extclients = append(extclients, extclient)
 		}
-		// add item our array of extclients
-		extclients = append(extclients, extclient)
-	}
-	//TODO: Another fatal error we should take care of.
-	if err := cur.Err(); err != nil {
-		return []models.ExtClient{}, err
 	}
-	return extclients, nil
+	return extclients, err
 }
 
 //A separate function to get all extclients, not just extclients for a particular network.
 //Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
 func getAllExtClients(w http.ResponseWriter, r *http.Request) {
+
 	w.Header().Set("Content-Type", "application/json")
-	extclients, err := functions.GetAllExtClients()
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+
+	headerNetworks := r.Header.Get("networks")
+	networksSlice := []string{}
+	marshalErr := json.Unmarshal([]byte(headerNetworks), &networksSlice)
+	if marshalErr != nil {
+		returnErrorResponse(w, r, formatError(marshalErr, "internal"))
 		return
 	}
+	clients := []models.ExtClient{}
+	err := errors.New("Networks Error")
+	if networksSlice[0] == ALL_NETWORK_ACCESS {
+		clients, err = functions.GetAllExtClients()
+		if err != nil && !database.IsEmptyRecord(err){
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	} else {
+		for _, network := range networksSlice {
+			extclients, err := GetNetworkExtClients(network)
+			if err == nil {
+				clients = append(clients, extclients...)
+			}
+		}
+	}
+
 	//Return all the extclients in JSON format
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(extclients)
+	json.NewEncoder(w).Encode(clients)
 }
 
 //Get an individual extclient. Nothin fancy here folks.
@@ -149,58 +116,60 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
 
-	var extclient models.ExtClient
-
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": params["network"], "clientid": params["clientid"]}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&extclient)
+	clientid := params["clientid"]
+	network := params["network"]
+	client, err := GetExtClient(clientid, network)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
-	defer cancel()
-
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(extclient)
+	json.NewEncoder(w).Encode(client)
 }
 
-//Get an individual extclient. Nothin fancy here folks.
-func getExtClientConf(w http.ResponseWriter, r *http.Request) {
-        // set header.
-        w.Header().Set("Content-Type", "application/json")
-
-        var params = mux.Vars(r)
+func GetExtClient(clientid string, network string) (models.ExtClient, error) {
+	var extclient models.ExtClient
+	key, err := functions.GetRecordKey(clientid, network)
+	if err != nil {
+		return extclient, err
+	}
+	data, err := database.FetchRecord(database.EXT_CLIENT_TABLE_NAME, key)
+	if err != nil {
+		return extclient, err
+	}
+	err = json.Unmarshal([]byte(data), &extclient)
 
-        var extclient models.ExtClient
+	return extclient, err
+}
 
-        collection := mongoconn.Client.Database("netmaker").Collection("extclients")
+//Get an individual extclient. Nothin fancy here folks.
+func getExtClientConf(w http.ResponseWriter, r *http.Request) {
+	// set header.
+	w.Header().Set("Content-Type", "application/json")
 
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	var params = mux.Vars(r)
+	clientid := params["clientid"]
+	networkid := params["network"]
+	client, err := GetExtClient(clientid, networkid)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 
-        filter := bson.M{"network": params["network"], "clientid": params["clientid"]}
-        err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&extclient)
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+	gwnode, err := functions.GetNodeByMacAddress(client.Network, client.IngressGatewayID)
+	if err != nil {
+		functions.PrintUserLog(r.Header.Get("user"),"Could not retrieve Ingress Gateway Node " + client.IngressGatewayID,1)
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 
-        gwnode, err := functions.GetNodeByMacAddress(extclient.Network, extclient.IngressGatewayID)
-        if err != nil {
-		fmt.Println("Could not retrieve Ingress Gateway Node " + extclient.IngressGatewayID)
+	network, err := functions.GetParentNetwork(client.Network)
+	if err != nil {
+		functions.PrintUserLog(r.Header.Get("user"),"Could not retrieve Ingress Gateway Network " + client.Network,1)
 		returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-
-	network, err := functions.GetParentNetwork(extclient.Network)
-        if err != nil {
-                fmt.Println("Could not retrieve Ingress Gateway Network " + extclient.Network)
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+		return
+	}
 	keepalive := ""
 	if network.DefaultKeepalive != 0 {
 		keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
@@ -216,12 +185,12 @@ AllowedIPs = %s
 Endpoint = %s
 %s
 
-`, extclient.Address + "/32",
-   extclient.PrivateKey,
-   gwnode.PublicKey,
-   network.AddressRange,
-   gwendpoint,
-   keepalive)
+`, client.Address+"/32",
+		client.PrivateKey,
+		gwnode.PublicKey,
+		network.AddressRange,
+		gwendpoint,
+		keepalive)
 
 	if params["type"] == "qr" {
 		bytes, err := qrcode.Encode(config, qrcode.Medium, 220)
@@ -240,21 +209,19 @@ Endpoint = %s
 	}
 
 	if params["type"] == "file" {
-		name := extclient.ClientID + ".conf"
-                w.Header().Set("Content-Type", "application/config")
-		w.Header().Set("Content-Disposition", "attachment; filename=\"" + name + "\"")
+		name := client.ClientID + ".conf"
+		w.Header().Set("Content-Type", "application/config")
+		w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
 		w.WriteHeader(http.StatusOK)
 		_, err := fmt.Fprint(w, config)
 		if err != nil {
-                        returnErrorResponse(w, r, formatError(err, "internal"))
+			returnErrorResponse(w, r, formatError(err, "internal"))
 		}
 		return
 	}
-
-        defer cancel()
-
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(extclient)
+	functions.PrintUserLog(r.Header.Get("user"),"retrieved ext client config",2)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(client)
 }
 
 func CreateExtClient(extclient models.ExtClient) error {
@@ -276,31 +243,30 @@ func CreateExtClient(extclient models.ExtClient) error {
 		extclient.Address = newAddress
 	}
 
-        if extclient.ClientID == "" {
-                clientid := StringWithCharset(7, charset)
-                clientname := "client-" + clientid
-                extclient.ClientID = clientname
-        }
+	if extclient.ClientID == "" {
+		extclient.ClientID = models.GenerateNodeName()
+	}
 
 	extclient.LastModified = time.Now().Unix()
 
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// insert our network into the network table
-	_, err := collection.InsertOne(ctx, extclient)
-	defer cancel()
+	key, err := functions.GetRecordKey(extclient.ClientID, extclient.Network)
 	if err != nil {
 		return err
 	}
-
+	data, err := json.Marshal(&extclient)
+	if err != nil {
+		return err
+	}
+	if err = database.Insert(key, string(data), database.EXT_CLIENT_TABLE_NAME); err != nil {
+		return err
+	}
 	err = SetNetworkNodesLastModified(extclient.Network)
-
 	return err
 }
-
-//This one's a doozy
-//To create a extclient
-//Must have valid key and be unique
+/**
+ * To create a extclient
+ * Must have valid key and be unique
+ */
 func createExtClient(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -308,9 +274,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 
 	networkName := params["network"]
 	macaddress := params["macaddress"]
-	//Check if network exists  first
-	//TODO: This is inefficient. Let's find a better way.
-	//Just a few rows down we grab the network anyway
 	ingressExists := checkIngressExists(networkName, macaddress)
 	if !ingressExists {
 		returnErrorResponse(w, r, formatError(errors.New("ingress does not exist"), "internal"))
@@ -322,9 +285,9 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	extclient.IngressGatewayID = macaddress
 	node, err := functions.GetNodeByMacAddress(networkName, macaddress)
 	if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	extclient.IngressGatewayEndpoint = node.Endpoint + ":" + strconv.FormatInt(int64(node.ListenPort), 10)
 
 	err = json.NewDecoder(r.Body).Decode(&extclient)
@@ -332,11 +295,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	err = ValidateExtClientCreate(params["network"], extclient)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
 	err = CreateExtClient(extclient)
 
 	if err != nil {
@@ -353,79 +311,69 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 
 	var newExtClient models.ExtClient
 	var oldExtClient models.ExtClient
-	// we decode our body request params
 	_ = json.NewDecoder(r.Body).Decode(&newExtClient)
-	// TODO: Validation for update.
-	// err := ValidateExtClientUpdate(params["network"], params["clientid"], newExtClient)
-	// if err != nil {
-	// 	returnErrorResponse(w, r, formatError(err, "badrequest"))
-	// 	return
-	// }
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"network": params["network"], "clientid": params["clientid"]}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&oldExtClient)
+
+	key, err := functions.GetRecordKey(params["clientid"], params["network"])
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	data, err := database.FetchRecord(database.EXT_CLIENT_TABLE_NAME, key)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	if err = json.Unmarshal([]byte(data), &oldExtClient); err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	newclient, err := UpdateExtClient(newExtClient.ClientID, params["network"], oldExtClient)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
+	functions.PrintUserLog(r.Header.Get("user"), "updated client "+newExtClient.ClientID, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(newclient)
 }
 
 func UpdateExtClient(newclientid string, network string, client models.ExtClient) (models.ExtClient, error) {
 
-        //collection := mongoconn.ConnectDB()
-        collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        // Create filter
-	filter := bson.M{"clientid": client.ClientID, "network": network}
-
-        // prepare update model.
-        update := bson.D{
-                {"$set", bson.D{
-                        {"clientid", newclientid},
-                }},
-        }
-        var clientupdate models.ExtClient
-
-        err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&clientupdate)
-
-        defer cancel()
-
-        return clientupdate, err
+	err := DeleteExtClient(network, client.ClientID)
+	if err != nil {
+		return client, err
+	}
+	client.ClientID = newclientid
+	CreateExtClient(client)
+	return client, err
 }
 
-func DeleteExtClient(network string, clientid string) (bool, error) {
-
-	deleted := false
-
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-
-	filter := bson.M{"network": network, "clientid": clientid}
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	result, err := collection.DeleteOne(ctx, filter)
-
-	deletecount := result.DeletedCount
-
-	if deletecount > 0 {
-		deleted = true
+func DeleteExtClient(network string, clientid string) error {
+	key, err := functions.GetRecordKey(clientid, network)
+	if err != nil {
+		return err
 	}
+	err = database.DeleteRecord(database.EXT_CLIENT_TABLE_NAME, key)
+	return err
+}
 
-	defer cancel()
-
-	fmt.Println("Deleted extclient client " + clientid + " from network " + network)
-	return deleted, err
+/**
+ * Deletes ext clients based on gateway (mac) of ingress node and network
+ */
+func DeleteGatewayExtClients(gatewayID string, networkName string) error {
+	currentExtClients, err := GetNetworkExtClients(networkName)
+	if err != nil {
+		return err
+	}
+	for _, extClient := range currentExtClients {
+		if extClient.IngressGatewayID == gatewayID {
+			if err = DeleteExtClient(networkName, extClient.ClientID); err != nil {
+				functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to remove ext client "+extClient.ClientID, 2)
+				continue
+			}
+		}
+	}
+	return nil
 }
 
 //Delete a extclient
@@ -437,28 +385,27 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 	// get params
 	var params = mux.Vars(r)
 
-	success, err := DeleteExtClient(params["network"], params["clientid"])
+	err := DeleteExtClient(params["network"], params["clientid"])
 
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	} else if !success {
 		err = errors.New("Could not delete extclient " + params["clientid"])
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"),
+		"Deleted extclient client "+params["clientid"]+" from network "+params["network"], 1)
 	returnSuccessResponse(w, r, params["clientid"]+" deleted.")
 }
 
 func StringWithCharset(length int, charset string) string {
-        b := make([]byte, length)
-        for i := range b {
-                b[i] = charset[seededRand.Intn(len(charset))]
-        }
-        return string(b)
+	b := make([]byte, length)
+	for i := range b {
+		b[i] = charset[seededRand.Intn(len(charset))]
+	}
+	return string(b)
 }
 
 const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 
 var seededRand *rand.Rand = rand.New(
-        rand.NewSource(time.Now().UnixNano()))
+	rand.NewSource(time.Now().UnixNano()))

+ 0 - 207
controllers/intClientHttpController.go

@@ -1,207 +0,0 @@
-package controller
-
-import (
-	//	"fmt"
-	// "github.com/davecgh/go-spew/spew"
-	"errors"
-	"context"
-	"encoding/json"
-	"net/http"
-	"time"
-	"github.com/gorilla/mux"
-	"github.com/gravitl/netmaker/functions"
-	"github.com/gravitl/netmaker/serverctl"
-	"github.com/gravitl/netmaker/servercfg"
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-)
-
-func intClientHandlers(r *mux.Router) {
-
-	r.HandleFunc("/api/intclient/{clientid}", securityCheck(http.HandlerFunc(getIntClient))).Methods("GET")
-	r.HandleFunc("/api/intclients", securityCheck(http.HandlerFunc(getAllIntClients))).Methods("GET")
-        r.HandleFunc("/api/intclients/deleteall", securityCheck(http.HandlerFunc(deleteAllIntClients))).Methods("DELETE")
-        r.HandleFunc("/api/intclient/{clientid}", securityCheck(http.HandlerFunc(updateIntClient))).Methods("PUT")
-	r.HandleFunc("/api/intclient/register", http.HandlerFunc(registerIntClient)).Methods("POST")
-	r.HandleFunc("/api/intclient/{clientid}", http.HandlerFunc(deleteIntClient)).Methods("DELETE")
-}
-
-func getAllIntClients(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        clients, err := functions.GetAllIntClients()
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        //Return all the extclients in JSON format
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(clients)
-}
-
-func deleteAllIntClients(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        err := functions.DeleteAllIntClients()
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
-}
-
-func deleteIntClient(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        // get params
-        var params = mux.Vars(r)
-
-        success, err := DeleteIntClient(params["clientid"])
-
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        } else if !success {
-                err = errors.New("Could not delete intclient " + params["clientid"])
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        returnSuccessResponse(w, r, params["clientid"]+" deleted.")
-}
-
-
-func getIntClient(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        var params = mux.Vars(r)
-
-	client, err := GetIntClient(params["clientid"])
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(client)
-}
-
-func updateIntClient(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-
-        var errorResponse = models.ErrorResponse{
-                Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
-        }
-
-        var clientreq models.IntClient
-
-        //get node from body of request
-        err := json.NewDecoder(r.Body).Decode(&clientreq)
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        if servercfg.IsRegisterKeyRequired() {
-                validKey := functions.IsKeyValidGlobal(clientreq.AccessKey)
-                if !validKey {
-                                errorResponse = models.ErrorResponse{
-                                        Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
-                                }
-                                returnErrorResponse(w, r, errorResponse)
-                                return
-                }
-        }
-        client, err := RegisterIntClient(clientreq)
-
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(client)
-}
-
-func RegisterIntClient(client models.IntClient) (models.IntClient, error) {
-	if client.PrivateKey == "" {
-		privateKey, err := wgtypes.GeneratePrivateKey()
-		if err != nil {
-			return client, err
-		}
-
-		client.PrivateKey = privateKey.String()
-		client.PublicKey = privateKey.PublicKey().String()
-	}
-
-	if client.Address == "" {
-		newAddress, err := functions.UniqueAddress(client.Network)
-		if err != nil {
-			return client, err
-		}
-		if newAddress == "" {
-			return client, errors.New("Could not find an address.")
-		}
-		client.Address = newAddress
-	}
-        if client.Network == "" { client.Network = "comms" }
-	server, err := serverctl.GetServerWGConf()
-        //spew.Dump(server)
-	if err != nil {
-                return client, err
-        }
-	client.ServerPublicEndpoint = server.ServerPublicEndpoint
-        client.ServerAPIPort = server.ServerAPIPort
-        client.ServerPrivateAddress = server.ServerPrivateAddress
-        client.ServerWGPort = server.ServerWGPort
-        client.ServerGRPCPort = server.ServerGRPCPort
-        client.ServerKey = server.ServerKey
-
-        if client.ClientID == "" {
-                clientid := StringWithCharset(7, charset)
-                clientname := "client-" + clientid
-                client.ClientID = clientname
-        }
-
-	//spew.Dump(client)
-	collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// insert our network into the network table
-	_, err = collection.InsertOne(ctx, client)
-	defer cancel()
-
-	if err != nil {
-		return client, err
-	}
-
-	err = serverctl.ReconfigureServerWireGuard()
-
-	return client, err
-}
-func registerIntClient(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-
-        var errorResponse = models.ErrorResponse{
-                Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
-        }
-
-        var clientreq models.IntClient
-
-        //get node from body of request
-        err := json.NewDecoder(r.Body).Decode(&clientreq)
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        if servercfg.IsRegisterKeyRequired() {
-                validKey := functions.IsKeyValidGlobal(clientreq.AccessKey)
-                if !validKey {
-                                errorResponse = models.ErrorResponse{
-                                        Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
-                                }
-                                returnErrorResponse(w, r, errorResponse)
-                                return
-                }
-        }
-        client, err := RegisterIntClient(clientreq)
-
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(client)
-}

+ 257 - 394
controllers/networkHttpController.go

@@ -1,43 +1,43 @@
 package controller
 
 import (
-	"context"
 	"encoding/base64"
 	"encoding/json"
 	"errors"
-	"fmt"
 	"net/http"
 	"strings"
 	"time"
 
 	"github.com/go-playground/validator/v10"
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/gravitl/netmaker/servercfg"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo"
-	"go.mongodb.org/mongo-driver/mongo/options"
+	"github.com/gravitl/netmaker/serverctl"
 )
 
+const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
+const NO_NETWORKS_PRESENT = "THIS_USER_HAS_NONE"
+
 func networkHandlers(r *mux.Router) {
-	r.HandleFunc("/api/networks", securityCheck(http.HandlerFunc(getNetworks))).Methods("GET")
-	r.HandleFunc("/api/networks", securityCheck(http.HandlerFunc(createNetwork))).Methods("POST")
-	r.HandleFunc("/api/networks/{networkname}", securityCheck(http.HandlerFunc(getNetwork))).Methods("GET")
-	r.HandleFunc("/api/networks/{networkname}", securityCheck(http.HandlerFunc(updateNetwork))).Methods("PUT")
-	r.HandleFunc("/api/networks/{networkname}", securityCheck(http.HandlerFunc(deleteNetwork))).Methods("DELETE")
-	r.HandleFunc("/api/networks/{networkname}/keyupdate", securityCheck(http.HandlerFunc(keyUpdate))).Methods("POST")
-	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(http.HandlerFunc(createAccessKey))).Methods("POST")
-	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(http.HandlerFunc(getAccessKeys))).Methods("GET")
-        r.HandleFunc("/api/networks/{networkname}/signuptoken", securityCheck(http.HandlerFunc(getSignupToken))).Methods("GET")
-	r.HandleFunc("/api/networks/{networkname}/keys/{name}", securityCheck(http.HandlerFunc(deleteAccessKey))).Methods("DELETE")
+	r.HandleFunc("/api/networks", securityCheck(false, http.HandlerFunc(getNetworks))).Methods("GET")
+	r.HandleFunc("/api/networks", securityCheck(true, http.HandlerFunc(createNetwork))).Methods("POST")
+	r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(getNetwork))).Methods("GET")
+	r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(updateNetwork))).Methods("PUT")
+	r.HandleFunc("/api/networks/{networkname}/nodelimit", securityCheck(true, http.HandlerFunc(updateNetworkNodeLimit))).Methods("PUT")
+	r.HandleFunc("/api/networks/{networkname}", securityCheck(true, http.HandlerFunc(deleteNetwork))).Methods("DELETE")
+	r.HandleFunc("/api/networks/{networkname}/keyupdate", securityCheck(false, http.HandlerFunc(keyUpdate))).Methods("POST")
+	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(createAccessKey))).Methods("POST")
+	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(getAccessKeys))).Methods("GET")
+	r.HandleFunc("/api/networks/{networkname}/signuptoken", securityCheck(false, http.HandlerFunc(getSignupToken))).Methods("GET")
+	r.HandleFunc("/api/networks/{networkname}/keys/{name}", securityCheck(false, http.HandlerFunc(deleteAccessKey))).Methods("DELETE")
 }
 
 //Security check is middleware for every function and just checks to make sure that its the master calling
 //Only admin should have access to all these network-level actions
 //or maybe some Users once implemented
-func securityCheck(next http.Handler) http.HandlerFunc {
+func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var errorResponse = models.ErrorResponse{
 			Code: http.StatusUnauthorized, Message: "W1R3: It's not you it's me.",
@@ -45,7 +45,7 @@ func securityCheck(next http.Handler) http.HandlerFunc {
 
 		var params = mux.Vars(r)
 		bearerToken := r.Header.Get("Authorization")
-		err := SecurityCheck(params["networkname"], bearerToken)
+		err, networks, username := SecurityCheck(reqAdmin, params["networkname"], bearerToken)
 		if err != nil {
 			if strings.Contains(err.Error(), "does not exist") {
 				errorResponse.Code = http.StatusNotFound
@@ -54,18 +54,19 @@ func securityCheck(next http.Handler) http.HandlerFunc {
 			returnErrorResponse(w, r, errorResponse)
 			return
 		}
+		networksJson, err := json.Marshal(&networks)
+		if err != nil {
+			errorResponse.Message = err.Error()
+			returnErrorResponse(w, r, errorResponse)
+			return
+		}
+		r.Header.Set("user", username)
+		r.Header.Set("networks", string(networksJson))
 		next.ServeHTTP(w, r)
 	}
 }
-func SecurityCheck(netname, token string) error {
-	hasnetwork := netname != ""
-	networkexists, err := functions.NetworkExists(netname)
-	if err != nil {
-		return err
-	}
-	if hasnetwork && !networkexists {
-		return errors.New("This network does not exist")
-	}
+
+func SecurityCheck(reqAdmin bool, netname string, token string) (error, []string, string) {
 
 	var hasBearer = true
 	var tokenSplit = strings.Split(token, " ")
@@ -76,14 +77,38 @@ func SecurityCheck(netname, token string) error {
 	} else {
 		authToken = tokenSplit[1]
 	}
+	userNetworks := []string{}
 	//all endpoints here require master so not as complicated
-	if !hasBearer || !authenticateMaster(authToken) {
-		_, isadmin, err := functions.VerifyUserToken(authToken)
-		if err != nil || !isadmin {
-			return errors.New("You are unauthorized to access this endpoint")
+	isMasterAuthenticated := authenticateMaster(authToken)
+	username := ""
+	if !hasBearer || !isMasterAuthenticated {
+		userName, networks, isadmin, err := functions.VerifyUserToken(authToken)
+		username = userName
+		if err != nil {
+			return errors.New("error verifying user token"), nil, username
+		}
+		if !isadmin && reqAdmin {
+			return errors.New("you are unauthorized to access this endpoint"), nil, username
+		}
+		userNetworks = networks
+		if isadmin {
+			userNetworks = []string{ALL_NETWORK_ACCESS}
+		} else {
+			networkexists, err := functions.NetworkExists(netname)
+			if err != nil && !database.IsEmptyRecord(err) {
+				return err, nil, ""
+			}
+			if netname != "" && !networkexists {
+				return errors.New("this network does not exist"), nil, ""
+			}
 		}
+	} else if isMasterAuthenticated {
+		userNetworks = []string{ALL_NETWORK_ACCESS}
 	}
-	return nil
+	if len(userNetworks) == 0 {
+		userNetworks = append(userNetworks, NO_NETWORKS_PRESENT)
+	}
+	return nil, userNetworks, username
 }
 
 //Consider a more secure way of setting master key
@@ -97,16 +122,32 @@ func authenticateMaster(tokenString string) bool {
 //simple get all networks function
 func getNetworks(w http.ResponseWriter, r *http.Request) {
 
-	allnetworks, err := functions.ListNetworks()
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+	headerNetworks := r.Header.Get("networks")
+	networksSlice := []string{}
+	marshalErr := json.Unmarshal([]byte(headerNetworks), &networksSlice)
+	if marshalErr != nil {
+		returnErrorResponse(w, r, formatError(marshalErr, "internal"))
 		return
 	}
-	networks := RemoveComms(allnetworks)
-
+	allnetworks := []models.Network{}
+	err := errors.New("Networks Error")
+	if networksSlice[0] == ALL_NETWORK_ACCESS {
+		allnetworks, err = models.GetNetworks()
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	} else {
+		for _, network := range networksSlice {
+			netObject, parentErr := functions.GetParentNetwork(network)
+			if parentErr == nil {
+				allnetworks = append(allnetworks, netObject)
+			}
+		}
+	}
+	functions.PrintUserLog(r.Header.Get("user"), "fetched networks.", 2)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(networks)
-	return
+	json.NewEncoder(w).Encode(allnetworks)
 }
 
 func RemoveComms(networks []models.Network) []models.Network {
@@ -124,78 +165,22 @@ func RemoveComms(networks []models.Network) []models.Network {
 	return append(returnable, networks[index+1:]...)
 }
 
-func ValidateNetworkUpdate(network models.NetworkUpdate) error {
+func ValidateNetworkUpdate(network models.Network) error {
 	v := validator.New()
 
-	//	_ = v.RegisterValidation("addressrange_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := fl.Field().String() == "" || functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-	//_ = v.RegisterValidation("addressrange6_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := fl.Field().String() == "" || functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-
-	//	_ = v.RegisterValidation("localrange_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := fl.Field().String() == "" || functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-
-	//	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
-	//		return true
-	//	})
-
-	//	_ = v.RegisterValidation("displayname_unique", func(fl validator.FieldLevel) bool {
-	//		return true
-	//	})
-
-	err := v.Struct(network)
-
-	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
-		}
-	}
-	return err
-}
-
-func ValidateNetworkCreate(network models.Network) error {
-
-	v := validator.New()
-
-	//	_ = v.RegisterValidation("addressrange_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-	_ = v.RegisterValidation("addressrange6_valid", func(fl validator.FieldLevel) bool {
-		isvalid := true
-		if *network.IsDualStack {
-			isvalid = functions.IsIpCIDR(fl.Field().String())
-		}
-		return isvalid
-	})
-	//
-	//	_ = v.RegisterValidation("localrange_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := fl.Field().String() == "" || functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-	//
 	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
-		isFieldUnique, _ := functions.IsNetworkNameUnique(fl.Field().String())
-		//		inCharSet := functions.NameInNetworkCharSet(fl.Field().String())
-		return isFieldUnique
-	})
-	//
-	_ = v.RegisterValidation("displayname_unique", func(fl validator.FieldLevel) bool {
-		isFieldUnique, _ := functions.IsNetworkDisplayNameUnique(fl.Field().String())
-		return isFieldUnique
+		if fl.Field().String() == "" {
+			return true
+		}
+		inCharSet := functions.NameInNetworkCharSet(fl.Field().String())
+		return inCharSet
 	})
 
 	err := v.Struct(network)
 
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+			functions.PrintUserLog("validator", e.Error(), 1)
 		}
 	}
 	return err
@@ -212,20 +197,22 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "fetched network "+netname, 2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(network)
 }
 
 func GetNetwork(name string) (models.Network, error) {
 	var network models.Network
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": name}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&network)
-	defer cancel()
+	record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, name)
 	if err != nil {
+		return network, err
+	}
+
+	if err = json.Unmarshal([]byte(record), &network); err != nil {
 		return models.Network{}, err
 	}
+
 	return network, nil
 }
 
@@ -238,71 +225,36 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "updated key on network "+netname, 2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(network)
 }
 
 func KeyUpdate(netname string) (models.Network, error) {
-	network, err := functions.GetParentNetwork(netname)
+	err := functions.NetworkNodesUpdateAction(netname, models.NODE_UPDATE_KEY)
 	if err != nil {
 		return models.Network{}, err
 	}
-	network.KeyUpdateTimeStamp = time.Now().Unix()
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": netname}
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"addressrange", network.AddressRange},
-			{"addressrange6", network.AddressRange6},
-			{"displayname", network.DisplayName},
-			{"defaultlistenport", network.DefaultListenPort},
-			{"defaultpostup", network.DefaultPostUp},
-			{"defaultpostdown", network.DefaultPostDown},
-			{"defaultkeepalive", network.DefaultKeepalive},
-			{"keyupdatetimestamp", network.KeyUpdateTimeStamp},
-			{"defaultsaveconfig", network.DefaultSaveConfig},
-			{"defaultinterface", network.DefaultInterface},
-			{"nodeslastmodified", network.NodesLastModified},
-			{"networklastmodified", network.NetworkLastModified},
-			{"allowmanualsignup", network.AllowManualSignUp},
-			{"checkininterval", network.DefaultCheckInInterval},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
-	if err != nil {
-		return models.Network{}, err
-	}
-	return network, nil
+	return models.Network{}, nil
 }
 
 //Update a network
 func AlertNetwork(netid string) error {
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": netid}
-
 	var network models.Network
-
 	network, err := functions.GetParentNetwork(netid)
 	if err != nil {
 		return err
 	}
 	updatetime := time.Now().Unix()
-	update := bson.D{
-		{"$set", bson.D{
-			{"nodeslastmodified", updatetime},
-			{"networklastmodified", updatetime},
-		}},
+	network.NodesLastModified = updatetime
+	network.NetworkLastModified = updatetime
+	data, err := json.Marshal(&network)
+	if err != nil {
+		return err
 	}
-
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
-
-	return err
+	database.Insert(netid, string(data), database.NETWORKS_TABLE_NAME)
+	return nil
 }
 
 //Update a network
@@ -310,155 +262,70 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	var network models.Network
-	network, err := functions.GetParentNetwork(params["networkname"])
+	netname := params["networkname"]
+	network, err := functions.GetParentNetwork(netname)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
-	var networkChange models.NetworkUpdate
-
-	_ = json.NewDecoder(r.Body).Decode(&networkChange)
-	if networkChange.AddressRange == "" {
-		networkChange.AddressRange = network.AddressRange
-	}
-	if networkChange.AddressRange6 == "" {
-		networkChange.AddressRange6 = network.AddressRange6
-	}
-	if networkChange.NetID == "" {
-		networkChange.NetID = network.NetID
-	}
-
-	err = ValidateNetworkUpdate(networkChange)
+	var newNetwork models.Network
+	err = json.NewDecoder(r.Body).Decode(&newNetwork)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
-	returnednetwork, err := UpdateNetwork(networkChange, network)
+	rangeupdate, localrangeupdate, err := network.Update(&newNetwork)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(returnednetwork)
-}
-
-func UpdateNetwork(networkChange models.NetworkUpdate, network models.Network) (models.Network, error) {
-	//NOTE: Network.NetID is intentionally NOT editable. It acts as a static ID for the network.
-	//DisplayName can be changed instead, which is what shows on the front end
-	if networkChange.NetID != network.NetID {
-		return models.Network{}, errors.New("NetID is not editable")
-	}
-
-	haschange := false
-	hasrangeupdate := false
-	haslocalrangeupdate := false
-
-	if networkChange.AddressRange != "" {
-		haschange = true
-		hasrangeupdate = true
-		network.AddressRange = networkChange.AddressRange
-	}
-	if networkChange.LocalRange != "" {
-		haschange = true
-		haslocalrangeupdate = true
-		network.LocalRange = networkChange.LocalRange
-	}
-	if networkChange.IsLocal != nil {
-		network.IsLocal = networkChange.IsLocal
-	}
-	if networkChange.IsDualStack != nil {
-		network.IsDualStack = networkChange.IsDualStack
-	}
-	if networkChange.DefaultListenPort != 0 {
-		network.DefaultListenPort = networkChange.DefaultListenPort
-		haschange = true
-	}
-	if networkChange.DefaultPostDown != "" {
-		network.DefaultPostDown = networkChange.DefaultPostDown
-		haschange = true
-	}
-	if networkChange.DefaultInterface != "" {
-		network.DefaultInterface = networkChange.DefaultInterface
-		haschange = true
-	}
-	if networkChange.DefaultPostUp != "" {
-		network.DefaultPostUp = networkChange.DefaultPostUp
-		haschange = true
-	}
-	if networkChange.DefaultKeepalive != 0 {
-		network.DefaultKeepalive = networkChange.DefaultKeepalive
-		haschange = true
-	}
-	if networkChange.DisplayName != "" {
-		network.DisplayName = networkChange.DisplayName
-		haschange = true
-	}
-	if networkChange.DefaultCheckInInterval != 0 {
-		network.DefaultCheckInInterval = networkChange.DefaultCheckInInterval
-		haschange = true
-	}
-	if networkChange.AllowManualSignUp != nil {
-		network.AllowManualSignUp = networkChange.AllowManualSignUp
-		haschange = true
-	}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": network.NetID}
-
-	if haschange {
-		network.SetNetworkLastModified()
-	}
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"addressrange", network.AddressRange},
-			{"addressrange6", network.AddressRange6},
-			{"displayname", network.DisplayName},
-			{"defaultlistenport", network.DefaultListenPort},
-			{"defaultpostup", network.DefaultPostUp},
-			{"defaultpostdown", network.DefaultPostDown},
-			{"defaultkeepalive", network.DefaultKeepalive},
-			{"defaultsaveconfig", network.DefaultSaveConfig},
-			{"defaultinterface", network.DefaultInterface},
-			{"nodeslastmodified", network.NodesLastModified},
-			{"networklastmodified", network.NetworkLastModified},
-			{"allowmanualsignup", network.AllowManualSignUp},
-			{"localrange", network.LocalRange},
-			{"islocal", network.IsLocal},
-			{"isdualstack", network.IsDualStack},
-			{"checkininterval", network.DefaultCheckInInterval},
-		}},
-	}
-
-	err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
-
-	if err != nil {
-		return models.Network{}, err
-	}
-
-	//Cycles through nodes and gives them new IP's based on the new range
-	//Pretty cool, but also pretty inefficient currently
-	if hasrangeupdate {
+	if rangeupdate {
 		err = functions.UpdateNetworkNodeAddresses(network.NetID)
 		if err != nil {
-			return models.Network{}, err
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
 		}
 	}
-	if haslocalrangeupdate {
-		err = functions.UpdateNetworkPrivateAddresses(network.NetID)
+	if localrangeupdate {
+		err = functions.UpdateNetworkLocalAddresses(network.NetID)
 		if err != nil {
-			return models.Network{}, err
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
 		}
 	}
-	returnnetwork, err := functions.GetParentNetwork(network.NetID)
+	functions.PrintUserLog(r.Header.Get("user"), "updated network "+netname, 1)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(newNetwork)
+}
+
+func updateNetworkNodeLimit(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	var network models.Network
+	netname := params["networkname"]
+	network, err := functions.GetParentNetwork(netname)
 	if err != nil {
-		return models.Network{}, err
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	var networkChange models.Network
+
+	_ = json.NewDecoder(r.Body).Decode(&networkChange)
+
+	if networkChange.NodeLimit != 0 {
+		network.NodeLimit = networkChange.NodeLimit
+		data, err := json.Marshal(&network)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "badrequest"))
+			return
+		}
+		database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME)
+		functions.PrintUserLog(r.Header.Get("user"), "updated network node limit on, "+netname, 1)
 	}
-	return returnnetwork, nil
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(network)
 }
 
 //Delete a network
@@ -469,45 +336,27 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
 	network := params["networkname"]
-	count, err := DeleteNetwork(network)
+	err := DeleteNetwork(network)
 
 	if err != nil {
 		errtype := "badrequest"
-		if strings.Contains(err.Error(), "Node check failed"){
+		if strings.Contains(err.Error(), "Node check failed") {
 			errtype = "forbidden"
 		}
 		returnErrorResponse(w, r, formatError(err, errtype))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "deleted network "+network, 1)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(count)
+	json.NewEncoder(w).Encode("success")
 }
 
-func DeleteNetwork(network string) (*mongo.DeleteResult, error) {
-	none := &mongo.DeleteResult{}
-
-	nodecount, err := functions.GetNetworkNodeNumber(network)
-	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "internal"))
-		return none, err
-	} else if nodecount > 0 {
-		//errorResponse := models.ErrorResponse{
-		//	Code: http.StatusForbidden, Message: "W1R3: Node check failed. All nodes must be deleted before deleting network.",
-		//}
-		//returnErrorResponse(w, r, errorResponse)
-		return none, errors.New("Node check failed. All nodes must be deleted before deleting network")
-	}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	filter := bson.M{"netid": network}
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	deleteResult, err := collection.DeleteOne(ctx, filter)
-	defer cancel()
-	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "internal"))
-		return none, err
+func DeleteNetwork(network string) error {
+	nodeCount, err := functions.GetNetworkNodeCount(network)
+	if nodeCount == 0 || database.IsEmptyRecord(err) {
+		return database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
 	}
-	return deleteResult, nil
+	return errors.New("node check failed. All nodes must be deleted before deleting network")
 }
 
 //Create a network
@@ -530,55 +379,51 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	success, err := serverctl.AddNetwork(network.NetID)
+	if err != nil || !success {
+		if err == nil {
+			err = errors.New("Failed to add server to network " + network.DisplayName)
+		}
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	functions.PrintUserLog(r.Header.Get("user"), "created network "+network.NetID, 1)
 	w.WriteHeader(http.StatusOK)
 	//json.NewEncoder(w).Encode(result)
 }
 
 func CreateNetwork(network models.Network) error {
-	//TODO: Not really doing good validation here. Same as createNode, updateNode, and updateNetwork
-	//Need to implement some better validation across the board
 
-	if network.IsLocal == nil {
-		falsevar := false
-		network.IsLocal = &falsevar
-	}
-	if network.IsDualStack == nil {
-		falsevar := false
-		network.IsDualStack = &falsevar
-	}
-
-	err := ValidateNetworkCreate(network)
-	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return err
-	}
 	network.SetDefaults()
 	network.SetNodesLastModified()
 	network.SetNetworkLastModified()
 	network.KeyUpdateTimeStamp = time.Now().Unix()
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	err := network.Validate(false)
+	if err != nil {
+		//returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return err
+	}
 
-	// insert our network into the network table
-	_, err = collection.InsertOne(ctx, network)
-	defer cancel()
+	data, err := json.Marshal(&network)
 	if err != nil {
 		return err
 	}
+	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return err
+	}
+
 	return nil
 }
 
 // BEGIN KEY MANAGEMENT SECTION
-
-//TODO: Very little error handling
-//accesskey is created as a json string inside the Network collection item in mongo
 func createAccessKey(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	var accesskey models.AccessKey
 	//start here
-	network, err := functions.GetParentNetwork(params["networkname"])
+	netname := params["networkname"]
+	network, err := functions.GetParentNetwork(netname)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -593,6 +438,7 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "created access key "+accesskey.Name+" on "+netname, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(key)
 	//w.Write([]byte(accesskey.AccessString))
@@ -611,85 +457,108 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 		accesskey.Uses = 1
 	}
 
-        checkkeys, err := GetKeys(network.NetID)
-        if err != nil {
-                return models.AccessKey{}, errors.New("could not retrieve network keys")
-        }
+	checkkeys, err := GetKeys(network.NetID)
+	if err != nil {
+		return models.AccessKey{}, errors.New("could not retrieve network keys")
+	}
 
 	for _, key := range checkkeys {
 		if key.Name == accesskey.Name {
-			return models.AccessKey{}, errors.New("Duplicate AccessKey Name")
+			return models.AccessKey{}, errors.New("duplicate AccessKey Name")
 		}
 	}
 	privAddr := ""
-	if network.IsLocal != nil {
-		if *network.IsLocal {
-			privAddr = network.LocalRange
-		}
+	if network.IsLocal != "" {
+		privAddr = network.LocalRange
 	}
 
 	netID := network.NetID
-	grpcaddress := servercfg.GetGRPCHost() + ":" + servercfg.GetGRPCPort()
-	apiaddress := servercfg.GetAPIHost() + ":" + servercfg.GetAPIPort()
-	wgport := servercfg.GetGRPCWGPort()
 
-	accessstringdec := wgport + "|" +grpcaddress + "|" + apiaddress + "|" + netID + "|" + accesskey.Value + "|" + privAddr
-	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(accessstringdec))
+	var accessToken models.AccessToken
+	s := servercfg.GetServerConfig()
+	servervals := models.ServerConfig{
+		CoreDNSAddr:    s.CoreDNSAddr,
+		APIConnString:  s.APIConnString,
+		APIHost:        s.APIHost,
+		APIPort:        s.APIPort,
+		GRPCConnString: s.GRPCConnString,
+		GRPCHost:       s.GRPCHost,
+		GRPCPort:       s.GRPCPort,
+		GRPCSSL:        s.GRPCSSL,
+	}
+	accessToken.ServerConfig = servervals
+	accessToken.ClientConfig.Network = netID
+	accessToken.ClientConfig.Key = accesskey.Value
+	accessToken.ClientConfig.LocalRange = privAddr
+
+	tokenjson, err := json.Marshal(accessToken)
+	if err != nil {
+		return accesskey, err
+	}
+
+	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
+
 	//validate accesskey
 	v := validator.New()
 	err = v.Struct(accesskey)
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+			functions.PrintUserLog("validator", e.Error(), 1)
 		}
 		return models.AccessKey{}, err
 	}
+
 	network.AccessKeys = append(network.AccessKeys, accesskey)
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"netid": network.NetID}
-	// Read update model from body request
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"accesskeys", network.AccessKeys},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
+	data, err := json.Marshal(&network)
 	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "internal"))
 		return models.AccessKey{}, err
 	}
+	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return models.AccessKey{}, err
+	}
+
 	return accesskey, nil
 }
 
 func GetSignupToken(netID string) (models.AccessKey, error) {
 
 	var accesskey models.AccessKey
-        address := servercfg.GetGRPCHost() + ":" + servercfg.GetGRPCPort()
+	var accessToken models.AccessToken
+	s := servercfg.GetServerConfig()
+	servervals := models.ServerConfig{
+		APIConnString:  s.APIConnString,
+		APIHost:        s.APIHost,
+		APIPort:        s.APIPort,
+		GRPCConnString: s.GRPCConnString,
+		GRPCHost:       s.GRPCHost,
+		GRPCPort:       s.GRPCPort,
+		GRPCSSL:        s.GRPCSSL,
+	}
+	accessToken.ServerConfig = servervals
 
-        accessstringdec := address + "|" + netID + "|" + "" + "|"
-        accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(accessstringdec))
-        return accesskey, nil
+	tokenjson, err := json.Marshal(accessToken)
+	if err != nil {
+		return accesskey, err
+	}
+
+	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
+	return accesskey, nil
 }
 func getSignupToken(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        var params = mux.Vars(r)
-        netID := params["networkname"]
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	netID := params["networkname"]
 
 	token, err := GetSignupToken(netID)
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(token)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	functions.PrintUserLog(r.Header.Get("user"), "got signup token "+netID, 2)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(token)
 }
 
-
-
 //pretty simple get
 func getAccessKeys(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
@@ -700,17 +569,17 @@ func getAccessKeys(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "fetched access keys on network "+network, 2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(keys)
 }
 func GetKeys(net string) ([]models.AccessKey, error) {
 
-	var network models.Network
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": net}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&network)
-	defer cancel()
+	record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, net)
+	if err != nil {
+		return []models.AccessKey{}, err
+	}
+	network, err := functions.ParseNetwork(record)
 	if err != nil {
 		return []models.AccessKey{}, err
 	}
@@ -728,6 +597,7 @@ func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "deleted access key "+keyname+" on network "+netname, 1)
 	w.WriteHeader(http.StatusOK)
 }
 func DeleteKey(keyname, netname string) error {
@@ -749,21 +619,14 @@ func DeleteKey(keyname, netname string) error {
 	if !found {
 		return errors.New("key " + keyname + " does not exist")
 	}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"netid": netname}
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"accesskeys", updatedKeys},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
+	network.AccessKeys = updatedKeys
+	data, err := json.Marshal(&network)
 	if err != nil {
 		return err
 	}
+	if err := database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return err
+	}
+
 	return nil
 }

+ 13 - 19
controllers/networkHttpController_test.go

@@ -20,19 +20,17 @@ func deleteNet(t *testing.T) {
 	assert.Nil(t, err)
 	for _, node := range nodes {
 		t.Log("deleting node", node.Name)
-		result, err := DeleteNode(node.MacAddress, node.Network)
+		err := DeleteNode(node.MacAddress, node.Network)
 		assert.Nil(t, err)
-		assert.True(t, result)
 	}
 	dns, err := GetAllDNS()
 	assert.Nil(t, err)
 	for _, entry := range dns {
 		t.Log("deleting dns enty", entry.Name, entry.Network)
-		success, err := DeleteDNS(entry.Name, entry.Network)
+		err := DeleteDNS(entry.Name, entry.Network)
 		assert.Nil(t, err)
-		assert.True(t, success)
 	}
-	networks, _ := functions.ListNetworks()
+	networks, _ := models.GetNetworks()
 	for _, network := range networks {
 		t.Log("deleting network", network.NetID)
 		success, err := DeleteNetwork(network.NetID)
@@ -56,7 +54,7 @@ func getNet() models.Network {
 }
 
 func TestGetNetworks(t *testing.T) {
-	//calls functions.ListNetworks --- nothing to be done
+	//calls models.GetNetworks --- nothing to be done
 }
 func TestCreateNetwork(t *testing.T) {
 	deleteNet(t)
@@ -78,10 +76,8 @@ func TestGetDeleteNetwork(t *testing.T) {
 		assert.Equal(t, "skynet", network.NetID)
 	})
 	t.Run("DeleteExistingNetwork", func(t *testing.T) {
-		result, err := DeleteNetwork("skynet")
+		err := DeleteNetwork("skynet")
 		assert.Nil(t, err)
-		assert.Equal(t, int64(1), result.DeletedCount)
-		t.Log(result.DeletedCount)
 	})
 	t.Run("GetNonExistantNetwork", func(t *testing.T) {
 		network, err := GetNetwork("skynet")
@@ -90,10 +86,8 @@ func TestGetDeleteNetwork(t *testing.T) {
 		assert.Equal(t, "", network.NetID)
 	})
 	t.Run("NonExistantNetwork", func(t *testing.T) {
-		result, err := DeleteNetwork("skynet")
+		err := DeleteNetwork("skynet")
 		assert.Nil(t, err)
-		assert.Equal(t, int64(0), result.DeletedCount)
-		t.Log(result.DeletedCount)
 	})
 }
 func TestGetNetwork(t *testing.T) {
@@ -114,14 +108,14 @@ func TestUpdateNetwork(t *testing.T) {
 	createNet()
 	network := getNet()
 	t.Run("NetID", func(t *testing.T) {
-		var networkupdate models.NetworkUpdate
+		var networkupdate models.Network
 		networkupdate.NetID = "wirecat"
 		_, err := UpdateNetwork(networkupdate, network)
 		assert.NotNil(t, err)
 		assert.Equal(t, "NetID is not editable", err.Error())
 	})
 	t.Run("LocalRange", func(t *testing.T) {
-		var networkupdate models.NetworkUpdate
+		var networkupdate models.Network
 		//NetID needs to be set as it will be in updateNetwork
 		networkupdate.NetID = "skynet"
 		networkupdate.LocalRange = "192.168.0.1/24"
@@ -259,20 +253,20 @@ func TestDeleteKey(t *testing.T) {
 }
 func TestSecurityCheck(t *testing.T) {
 	t.Run("NoNetwork", func(t *testing.T) {
-		err := SecurityCheck("", "Bearer secretkey")
+		err := SecurityCheck(false, "", "Bearer secretkey")
 		assert.Nil(t, err)
 	})
 	t.Run("WithNetwork", func(t *testing.T) {
-		err := SecurityCheck("skynet", "Bearer secretkey")
+		err := SecurityCheck(false, "skynet", "Bearer secretkey")
 		assert.Nil(t, err)
 	})
 	t.Run("BadNet", func(t *testing.T) {
-		err := SecurityCheck("badnet", "Bearer secretkey")
+		err := SecurityCheck(false, "badnet", "Bearer secretkey")
 		assert.NotNil(t, err)
 		t.Log(err)
 	})
 	t.Run("BadToken", func(t *testing.T) {
-		err := SecurityCheck("skynet", "Bearer badkey")
+		err := SecurityCheck(false, "skynet", "Bearer badkey")
 		assert.NotNil(t, err)
 		t.Log(err)
 	})
@@ -378,7 +372,7 @@ func TestValidateNetworkUpdate(t *testing.T) {
 	}
 	for _, tc := range cases {
 		t.Run(tc.testname, func(t *testing.T) {
-			network := models.NetworkUpdate(tc.network)
+			network := models.Network(tc.network)
 			err := ValidateNetworkUpdate(network)
 			assert.NotNil(t, err)
 			assert.Contains(t, err.Error(), tc.errMessage)

+ 106 - 370
controllers/nodeGrpcController.go

@@ -2,155 +2,49 @@ package controller
 
 import (
 	"context"
-	"fmt"
+	"encoding/json"
+	"errors"
+	"strings"
 	"github.com/gravitl/netmaker/functions"
 	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/servercfg"
-	"go.mongodb.org/mongo-driver/mongo"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/status"
 )
 
 type NodeServiceServer struct {
-	NodeDB *mongo.Collection
 	nodepb.UnimplementedNodeServiceServer
 }
 
-func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.ReadNodeReq) (*nodepb.ReadNodeRes, error) {
+func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 	// convert string id (from proto) to mongoDB ObjectId
-	macaddress := req.GetMacaddress()
-	networkName := req.GetNetwork()
-	network, _ := functions.GetParentNetwork(networkName)
-
-	node, err := GetNode(macaddress, networkName)
+	macAndNetwork := strings.Split(req.Data, "###")
 
+	if len(macAndNetwork) != 2 {
+		return nil, errors.New("could not read node, invalid node id given")
+	}
+	node, err := GetNode(macAndNetwork[0], macAndNetwork[1])
 	if err != nil {
-		return nil, status.Errorf(codes.InvalidArgument, fmt.Sprintf("Something went wrong: %v", err))
+		return nil, err
 	}
-
-	/*
-		if node == nil {
-			return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not find node with Mac Address %s: %v", req.GetMacaddress(), err))
-		}
-	*/
+	node.SetLastCheckIn()
 	// Cast to ReadNodeRes type
-	dualvar := false
-	if network.IsDualStack != nil {
-		dualvar = *network.IsDualStack
+	nodeData, err := json.Marshal(&node)
+	if err != nil {
+		return nil, err
 	}
-	localvar := false
-	if network.IsLocal != nil {
-		localvar = *network.IsLocal
-	}
-
-	response := &nodepb.ReadNodeRes{
-		Node: &nodepb.Node{
-			Macaddress:      node.MacAddress,
-			Name:            node.Name,
-			Address:         node.Address,
-			Address6:        node.Address6,
-			Endpoint:        node.Endpoint,
-			Password:        node.Password,
-			Nodenetwork:     node.Network,
-			Interface:       node.Interface,
-			Localaddress:    node.LocalAddress,
-			Postdown:        node.PostDown,
-			Postup:          node.PostUp,
-			Checkininterval: node.CheckInInterval,
-			Dnsoff:          !servercfg.IsDNSMode(),
-			Ispending:       node.IsPending,
-			Isingressgateway:       node.IsIngressGateway,
-			Ingressgatewayrange:       node.IngressGatewayRange,
-			Publickey:       node.PublicKey,
-			Listenport:      node.ListenPort,
-			Keepalive:       node.PersistentKeepalive,
-			Islocal:         localvar,
-			Isdualstack:     dualvar,
-			Localrange:      network.LocalRange,
-		},
+	node.Update(&node)
+	response := &nodepb.Object{
+		Data: string(nodeData),
+		Type: nodepb.NODE_TYPE,
 	}
 	return response, nil
 }
-/*
-func (s *NodeServiceServer) GetConn(ctx context.Context, data *nodepb.Client) (*nodepb.Client, error) {
-        // Get the protobuf node type from the protobuf request type
-        // Essentially doing req.Node to access the struct with a nil check
-        // Now we have to convert this into a NodeItem type to convert into BSON
-        clientreq := models.IntClient{
-                // ID:       primitive.NilObjectID,
-                Address:             data.GetAddress(),
-                Address6:            data.GetAddress6(),
-                AccessKey:           data.GetAccesskey(),
-                PublicKey:           data.GetPublickey(),
-                PrivateKey:           data.GetPrivatekey(),
-                ServerPort:          data.GetServerport(),
-                ServerKey:          data.GetServerkey(),
-                ServerWGEndpoint:          data.GetServerwgendpoint(),
-        }
 
-        //Check to see if key is valid
-        //TODO: Triple inefficient!!! This is the third call to the DB we make for networks
-        if servercfg.IsRegisterKeyRequired() {
-		validKey := functions.IsKeyValidGlobal(clientreq.AccessKey)
-		if !validKey {
-			return nil, status.Errorf(
-                                codes.Internal,
-                                fmt.Sprintf("Invalid key, and server does not allow no-key signups"),
-                        )
-		}
-	}
-	client, err := RegisterIntClient(clientreq)
-
-        if err != nil {
-                // return internal gRPC error to be handled later
-                return nil, status.Errorf(
-                        codes.Internal,
-                        fmt.Sprintf("Internal error: %v", err),
-                )
-        }
-        // return the node in a CreateNodeRes type
-        response := &nodepb.Client{
-                        Privatekey:   client.PrivateKey,
-                        Publickey: client.PublicKey,
-                        Accesskey:         client.AccessKey,
-                        Address:      client.Address,
-                        Address6:     client.Address6,
-                        Serverwgendpoint:     client.ServerWGEndpoint,
-                        Serverport:     client.ServerPort,
-                        Serverkey:    client.ServerKey,
-        }
-
-        return response, nil
-}
-*/
-func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNodeReq) (*nodepb.CreateNodeRes, error) {
+func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 	// Get the protobuf node type from the protobuf request type
 	// Essentially doing req.Node to access the struct with a nil check
-	data := req.GetNode()
-	// Now we have to convert this into a NodeItem type to convert into BSON
-	node := models.Node{
-		// ID:       primitive.NilObjectID,
-		MacAddress:          data.GetMacaddress(),
-		LocalAddress:        data.GetLocaladdress(),
-		Name:                data.GetName(),
-		Address:             data.GetAddress(),
-		Address6:            data.GetAddress6(),
-		AccessKey:           data.GetAccesskey(),
-		Endpoint:            data.GetEndpoint(),
-		PersistentKeepalive: data.GetKeepalive(),
-		Password:            data.GetPassword(),
-		Interface:           data.GetInterface(),
-		Network:             data.GetNodenetwork(),
-		IsPending:           data.GetIspending(),
-		PublicKey:           data.GetPublickey(),
-		ListenPort:          data.GetListenport(),
-	}
-
-	err := ValidateNodeCreate(node.Network, node)
-
-	if err != nil {
-		// return internal gRPC error to be handled later
+	var node models.Node
+	data := req.GetData()
+	if err := json.Unmarshal([]byte(data), &node); err != nil {
 		return nil, err
 	}
 
@@ -159,302 +53,144 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo
 	validKey := functions.IsKeyValid(node.Network, node.AccessKey)
 	network, err := functions.GetParentNetwork(node.Network)
 	if err != nil {
-		return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not find network: %v", err))
+		return nil, err
 	}
 
 	if !validKey {
 		//Check to see if network will allow manual sign up
 		//may want to switch this up with the valid key check and avoid a DB call that way.
-		if *network.AllowManualSignUp {
-			node.IsPending = true
+		if network.AllowManualSignUp == "yes" {
+			node.IsPending = "yes"
 		} else {
-			return nil, status.Errorf(
-				codes.Internal,
-				fmt.Sprintf("Invalid key, and network does not allow no-key signups"),
-			)
+			return nil, errors.New("invalid key, and network does not allow no-key signups")
 		}
 	}
 
 	node, err = CreateNode(node, node.Network)
-
 	if err != nil {
-		// return internal gRPC error to be handled later
-		return nil, status.Errorf(
-			codes.Internal,
-			fmt.Sprintf("Internal error: %v", err),
-		)
-	}
-	dualvar := false
-	if network.IsDualStack != nil {
-		dualvar = *network.IsDualStack
-	}
-	localvar := false
-	if network.IsLocal != nil {
-		localvar = *network.IsLocal
+		return nil, err
 	}
-
+	nodeData, err := json.Marshal(&node)
 	// return the node in a CreateNodeRes type
-	response := &nodepb.CreateNodeRes{
-		Node: &nodepb.Node{
-			Macaddress:   node.MacAddress,
-			Localaddress: node.LocalAddress,
-			Name:         node.Name,
-			Address:      node.Address,
-			Address6:     node.Address6,
-			Endpoint:     node.Endpoint,
-			Password:     node.Password,
-			Interface:    node.Interface,
-			Nodenetwork:  node.Network,
-			Dnsoff:       !servercfg.IsDNSMode(),
-			Ispending:    node.IsPending,
-			Publickey:    node.PublicKey,
-			Listenport:   node.ListenPort,
-			Keepalive:    node.PersistentKeepalive,
-			Islocal:      localvar,
-			Isdualstack:  dualvar,
-			Localrange:   network.LocalRange,
-		},
+	response := &nodepb.Object{
+		Data: string(nodeData),
+		Type: nodepb.NODE_TYPE,
 	}
 	err = SetNetworkNodesLastModified(node.Network)
 	if err != nil {
-		return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not update network last modified date: %v", err))
+		return nil, err
 	}
 
 	return response, nil
 }
 
-func (s *NodeServiceServer) CheckIn(ctx context.Context, req *nodepb.CheckInReq) (*nodepb.CheckInRes, error) {
-	// Get the protobuf node type from the protobuf request type
-	// Essentially doing req.Node to access the struct with a nil check
-	data := req.GetNode()
-	//postchanges := req.GetPostchanges()
-	// Now we have to convert this into a NodeItem type to convert into BSON
-	node := models.Node{
-		// ID:       primitive.NilObjectID,
-		MacAddress:          data.GetMacaddress(),
-		Address:             data.GetAddress(),
-		Address6:            data.GetAddress6(),
-		Endpoint:            data.GetEndpoint(),
-		Network:             data.GetNodenetwork(),
-		Password:            data.GetPassword(),
-		LocalAddress:        data.GetLocaladdress(),
-		ListenPort:          data.GetListenport(),
-		PersistentKeepalive: data.GetKeepalive(),
-		PublicKey:           data.GetPublickey(),
+func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
+	// Get the node data from the request
+	var newnode models.Node
+	if err := json.Unmarshal([]byte(req.GetData()), &newnode); err != nil {
+		return nil, err
 	}
+	macaddress := newnode.MacAddress
+	networkName := newnode.Network
 
-	checkinresponse, err := NodeCheckIn(node, node.Network)
-
+	node, err := functions.GetNodeByMacAddress(networkName, macaddress)
 	if err != nil {
-		// return internal gRPC error to be handled later
-		if checkinresponse == (models.CheckInResponse{}) || !checkinresponse.IsPending {
-			return nil, status.Errorf(
-				codes.Internal,
-				fmt.Sprintf("Internal error: %v", err),
-			)
-		}
-	}
-	// return the node in a CreateNodeRes type
-	response := &nodepb.CheckInRes{
-		Checkinresponse: &nodepb.CheckInResponse{
-			Success:          checkinresponse.Success,
-			Needpeerupdate:   checkinresponse.NeedPeerUpdate,
-			Needdelete:       checkinresponse.NeedDelete,
-			Needconfigupdate: checkinresponse.NeedConfigUpdate,
-			Needkeyupdate:    checkinresponse.NeedKeyUpdate,
-			Nodemessage:      checkinresponse.NodeMessage,
-			Ispending:        checkinresponse.IsPending,
-		},
-	}
-	return response, nil
-}
-
-func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNodeReq) (*nodepb.UpdateNodeRes, error) {
-	// Get the node data from the request
-	data := req.GetNode()
-	// Now we have to convert this into a NodeItem type to convert into BSON
-	nodechange := models.NodeUpdate{
-		// ID:       primitive.NilObjectID,
-		MacAddress:          data.GetMacaddress(),
-		Name:                data.GetName(),
-		Address:             data.GetAddress(),
-		Address6:            data.GetAddress6(),
-		LocalAddress:        data.GetLocaladdress(),
-		Endpoint:            data.GetEndpoint(),
-		Password:            data.GetPassword(),
-		PersistentKeepalive: data.GetKeepalive(),
-		Network:             data.GetNodenetwork(),
-		Interface:           data.GetInterface(),
-		PostDown:            data.GetPostdown(),
-		PostUp:              data.GetPostup(),
-		IsPending:           data.GetIspending(),
-		PublicKey:           data.GetPublickey(),
-		ListenPort:          data.GetListenport(),
+		return nil, err
 	}
 
-	// Convert the Id string to a MongoDB ObjectId
-	macaddress := nodechange.MacAddress
-	networkName := nodechange.Network
-	network, _ := functions.GetParentNetwork(networkName)
-
-	err := ValidateNodeUpdate(networkName, nodechange)
+	err = node.Update(&newnode)
 	if err != nil {
 		return nil, err
 	}
-
-	node, err := functions.GetNodeByMacAddress(networkName, macaddress)
+	nodeData, err := json.Marshal(&newnode)
 	if err != nil {
-		return nil, status.Errorf(
-			codes.NotFound,
-			fmt.Sprintf("Could not find node with supplied Mac Address: %v", err),
-		)
+		return nil, err
 	}
+	return &nodepb.Object{
+		Data: string(nodeData),
+		Type: nodepb.NODE_TYPE,
+	}, nil
+}
 
-	newnode, err := UpdateNode(nodechange, node)
+func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
+	nodeID := req.GetData()
 
+	err := DeleteNode(nodeID, true)
 	if err != nil {
-		return nil, status.Errorf(
-			codes.NotFound,
-			fmt.Sprintf("Could not find node with supplied Mac Address: %v", err),
-		)
-	}
-	dualvar := false
-	if network.IsDualStack != nil {
-		dualvar = *network.IsDualStack
-	}
-	localvar := false
-	if network.IsLocal != nil {
-		localvar = *network.IsLocal
+		return nil, err
 	}
 
-	return &nodepb.UpdateNodeRes{
-		Node: &nodepb.Node{
-			Macaddress:   newnode.MacAddress,
-			Localaddress: newnode.LocalAddress,
-			Name:         newnode.Name,
-			Address:      newnode.Address,
-			Address6:     newnode.Address6,
-			Endpoint:     newnode.Endpoint,
-			Password:     newnode.Password,
-			Interface:    newnode.Interface,
-			Postdown:     newnode.PostDown,
-			Postup:       newnode.PostUp,
-			Nodenetwork:  newnode.Network,
-			Ispending:    newnode.IsPending,
-			Publickey:    newnode.PublicKey,
-			Dnsoff:       !servercfg.IsDNSMode(),
-			Listenport:   newnode.ListenPort,
-			Keepalive:    newnode.PersistentKeepalive,
-			Islocal:      localvar,
-			Isdualstack:  dualvar,
-			Localrange:   network.LocalRange,
-		},
+	return &nodepb.Object{
+		Data: "success",
+		Type: nodepb.STRING_TYPE,
 	}, nil
 }
 
-func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.DeleteNodeReq) (*nodepb.DeleteNodeRes, error) {
-	macaddress := req.GetMacaddress()
-	network := req.GetNetworkName()
-
-	success, err := DeleteNode(macaddress, network)
-
-	if err != nil || !success {
-		fmt.Println("Error deleting node.")
-		fmt.Println(err)
-		return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not find/delete node with mac address %s", macaddress))
-	}
+func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
+	macAndNetwork := strings.Split(req.Data, "###")
+	if len(macAndNetwork) == 2 {
+		// TODO: Make constant and new variable for isServer
+		node, err := GetNode(macAndNetwork[0], macAndNetwork[1])
+		if err != nil {
+			return nil, err
+		}
+		if node.IsServer == "yes" {
+			SetNetworkServerPeers(macAndNetwork[1])
+		}
+		peers, err := GetPeersList(macAndNetwork[1])
+		if err != nil {
+			return nil, err
+		}
 
-	fmt.Println("updating network last modified of " + req.GetNetworkName())
-	err = SetNetworkNodesLastModified(req.GetNetworkName())
-	if err != nil {
-		fmt.Println("Error updating Network")
-		fmt.Println(err)
-		return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not update network last modified date: %v", err))
+		peersData, err := json.Marshal(&peers)
+		return &nodepb.Object{
+			Data: string(peersData),
+			Type: nodepb.NODE_TYPE,
+		}, err
 	}
-
-	return &nodepb.DeleteNodeRes{
-		Success: true,
-	}, nil
+	return &nodepb.Object{
+		Data: "",
+		Type: nodepb.NODE_TYPE,
+	}, errors.New("could not fetch peers, invalid node id")
 }
 
-func (s *NodeServiceServer) GetPeers(req *nodepb.GetPeersReq, stream nodepb.NodeService_GetPeersServer) error {
+/**
+ * Return Ext Peers (clients).NodeCheckIn
+ * When a gateway node checks in, it pulls these peers to add to peers list in addition to normal network peers.
+ */
+func (s *NodeServiceServer) GetExtPeers(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 	// Initiate a NodeItem type to write decoded data to
 	//data := &models.PeersResponse{}
 	// collection.Find returns a cursor for our (empty) query
-	//cursor, err := s.NodeDB.Find(context.Background(), bson.M{})
-	peers, err := GetPeersList(req.GetNetwork())
-
+	macAndNetwork := strings.Split(req.Data, "###")
+	if len(macAndNetwork) != 2 {
+		return nil, errors.New("did not receive valid node id when fetching ext peers")
+	}
+	peers, err := GetExtPeersList(macAndNetwork[0], macAndNetwork[1])
 	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Unknown internal error: %v", err))
+		return nil, err
 	}
 	// cursor.Next() returns a boolean, if false there are no more items and loop will break
+	var extPeers []models.Node
 	for i := 0; i < len(peers); i++ {
-
-		// If no error is found send node over stream
-		stream.Send(&nodepb.GetPeersRes{
-			Peers: &nodepb.PeersResponse{
-				Address:      peers[i].Address,
-				Address6:     peers[i].Address6,
-				Endpoint:     peers[i].Endpoint,
-				Egressgatewayrange: peers[i].EgressGatewayRange,
-				Isegressgateway:    peers[i].IsEgressGateway,
-				Publickey:    peers[i].PublicKey,
-				Keepalive:    peers[i].KeepAlive,
-				Listenport:   peers[i].ListenPort,
-				Localaddress: peers[i].LocalAddress,
-			},
+		extPeers = append(extPeers, models.Node{
+			Address:             peers[i].Address,
+			Address6:            peers[i].Address6,
+			Endpoint:            peers[i].Endpoint,
+			PublicKey:           peers[i].PublicKey,
+			PersistentKeepalive: peers[i].KeepAlive,
+			ListenPort:          peers[i].ListenPort,
+			LocalAddress:        peers[i].LocalAddress,
 		})
 	}
 
-	node, err := functions.GetNodeByMacAddress(req.GetNetwork(), req.GetMacaddress())
-	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Could not get node: %v", err))
-	}
-
-	err = TimestampNode(node, false, true, false)
+	extData, err := json.Marshal(&extPeers)
 	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Internal error occurred: %v", err))
+		return nil, err
 	}
 
-	return nil
-}
-
-func (s *NodeServiceServer) GetExtPeers(req *nodepb.GetExtPeersReq, stream nodepb.NodeService_GetExtPeersServer) error {
-        // Initiate a NodeItem type to write decoded data to
-        //data := &models.PeersResponse{}
-        // collection.Find returns a cursor for our (empty) query
-        //cursor, err := s.NodeDB.Find(context.Background(), bson.M{})
-        peers, err := GetExtPeersList(req.GetNetwork(), req.GetMacaddress())
-
-        if err != nil {
-                return status.Errorf(codes.Internal, fmt.Sprintf("Unknown internal error: %v", err))
-        }
-        // cursor.Next() returns a boolean, if false there are no more items and loop will break
-        for i := 0; i < len(peers); i++ {
-
-                // If no error is found send node over stream
-                stream.Send(&nodepb.GetExtPeersRes{
-                        Extpeers: &nodepb.ExtPeersResponse{
-                                Address:      peers[i].Address,
-                                Address6:     peers[i].Address6,
-                                Endpoint:     peers[i].Endpoint,
-                                Publickey:    peers[i].PublicKey,
-                                Keepalive:    peers[i].KeepAlive,
-                                Listenport:   peers[i].ListenPort,
-                                Localaddress: peers[i].LocalAddress,
-                        },
-                })
-        }
-
-        node, err := functions.GetNodeByMacAddress(req.GetNetwork(), req.GetMacaddress())
-        if err != nil {
-                return status.Errorf(codes.Internal, fmt.Sprintf("Could not get node: %v", err))
-        }
-
-        err = TimestampNode(node, false, true, false)
-        if err != nil {
-                return status.Errorf(codes.Internal, fmt.Sprintf("Internal error occurred: %v", err))
-        }
-
-        return nil
+	return &nodepb.Object{
+		Data: string(extData),
+		Type: nodepb.EXT_PEER,
+	}, nil
 }

+ 252 - 352
controllers/nodeHttpController.go

@@ -1,36 +1,32 @@
 package controller
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
-	"fmt"
 	"net/http"
 	"strings"
 	"time"
-	"log"
+
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo/options"
+	"github.com/gravitl/netmaker/servercfg"
 	"golang.org/x/crypto/bcrypt"
 )
 
 func nodeHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/nodes", authorize(false, "master", http.HandlerFunc(getAllNodes))).Methods("GET")
+	r.HandleFunc("/api/nodes", authorize(false, "user", http.HandlerFunc(getAllNodes))).Methods("GET")
 	r.HandleFunc("/api/nodes/{network}", authorize(true, "network", http.HandlerFunc(getNetworkNodes))).Methods("GET")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(getNode))).Methods("GET")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(updateNode))).Methods("PUT")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(deleteNode))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/checkin", authorize(true, "node", http.HandlerFunc(checkIn))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/creategateway", authorize(true, "master", http.HandlerFunc(createEgressGateway))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/deletegateway", authorize(true, "master", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/createingress", securityCheck(http.HandlerFunc(createIngressGateway))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/deleteingress", securityCheck(http.HandlerFunc(deleteIngressGateway))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/approve", authorize(true, "master", http.HandlerFunc(uncordonNode))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/creategateway", authorize(true, "user", http.HandlerFunc(createEgressGateway))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/deletegateway", authorize(true, "user", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/createingress", securityCheck(false, http.HandlerFunc(createIngressGateway))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/deleteingress", securityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods("DELETE")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/approve", authorize(true, "user", http.HandlerFunc(uncordonNode))).Methods("POST")
 	r.HandleFunc("/api/nodes/{network}", createNode).Methods("POST")
 	r.HandleFunc("/api/nodes/adm/{network}/lastmodified", authorize(true, "network", http.HandlerFunc(getLastModified))).Methods("GET")
 	r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods("POST")
@@ -40,6 +36,8 @@ func nodeHandlers(r *mux.Router) {
 //Node authenticates using its password and retrieves a JWT for authorization.
 func authenticate(response http.ResponseWriter, request *http.Request) {
 
+	var params = mux.Vars(request)
+	networkname := params["network"]
 	//Auth request consists of Mac Address and Password (from node that is authorizing
 	//in case of Master, auth is ignored and mac is set to "mastermac"
 	var authRequest models.AuthParams
@@ -71,11 +69,21 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 		} else {
 
 			//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
-			collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-			ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-			var err = collection.FindOne(ctx, bson.M{"macaddress": authRequest.MacAddress, "ispending": false}).Decode(&result)
-
-			defer cancel()
+			collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+			if err != nil {
+				errorResponse.Code = http.StatusBadRequest
+				errorResponse.Message = err.Error()
+				returnErrorResponse(response, request, errorResponse)
+				return
+			}
+			for _, value := range collection {
+				if err := json.Unmarshal([]byte(value), &result); err != nil {
+					continue
+				}
+				if result.MacAddress == authRequest.MacAddress && result.IsPending != "yes" && result.Network == networkname {
+					break
+				}
+			}
 
 			if err != nil {
 				errorResponse.Code = http.StatusBadRequest
@@ -138,7 +146,6 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 //TODO: Consider better RBAC implementations
 func authorize(networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-
 		var errorResponse = models.ErrorResponse{
 			Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
 		}
@@ -146,7 +153,6 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 		var params = mux.Vars(r)
 
 		networkexists, _ := functions.NetworkExists(params["network"])
-
 		//check that the request is for a valid network
 		//if (networkCheck && !networkexists) || err != nil {
 		if networkCheck && !networkexists {
@@ -155,9 +161,7 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 			}
 			returnErrorResponse(w, r, errorResponse)
 			return
-
 		} else {
-
 			w.Header().Set("Content-Type", "application/json")
 
 			//get the auth token
@@ -183,28 +187,24 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 			//A: the token is the master password
 			//B: the token corresponds to a mac address, and if so, which one
 			//TODO: There's probably a better way of dealing with the "master token"/master password. Plz Halp.
-
-                        var isAuthorized = false
+			var isAuthorized = false
 			var macaddress = ""
-                        _, isadmin, errN := functions.VerifyUserToken(authToken)
-                        if errN == nil && isadmin {
-	                        macaddress = "mastermac"
-                                isAuthorized = true
-			} else {
-				mac, _, err := functions.VerifyToken(authToken)
-				if err != nil {
-					errorResponse = models.ErrorResponse{
-						Code: http.StatusUnauthorized, Message: "W1R3: Error Verifying Auth Token.",
-					}
-					returnErrorResponse(w, r, errorResponse)
-					return
+			username, networks, isadmin, errN := functions.VerifyUserToken(authToken)
+			isnetadmin := isadmin
+			if errN == nil && isadmin {
+				macaddress = "mastermac"
+				isAuthorized = true
+				r.Header.Set("ismasterkey", "yes")
+			}
+			if !isadmin && params["network"] != "" {
+				if functions.SliceContains(networks, params["network"]) {
+					isnetadmin = true
 				}
-				macaddress = mac
 			}
 			//The mastermac (login with masterkey from config) can do everything!! May be dangerous.
 			if macaddress == "mastermac" {
 				isAuthorized = true
-
+				r.Header.Set("ismasterkey", "yes")
 				//for everyone else, there's poor man's RBAC. The "cases" are defined in the routes in the handlers
 				//So each route defines which access network should be allowed to access it
 			} else {
@@ -212,21 +212,29 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 				case "all":
 					isAuthorized = true
 				case "nodes":
-					isAuthorized = (macaddress != "")
+					isAuthorized = (macaddress != "") || isnetadmin
 				case "network":
-					node, err := functions.GetNodeByMacAddress(params["network"], macaddress)
-					if err != nil {
-						errorResponse = models.ErrorResponse{
-							Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.",
+					if isnetadmin {
+						isAuthorized = true
+					} else {
+						node, err := functions.GetNodeByMacAddress(params["network"], macaddress)
+						if err != nil {
+							errorResponse = models.ErrorResponse{
+								Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.",
+							}
+							returnErrorResponse(w, r, errorResponse)
+							return
 						}
-						returnErrorResponse(w, r, errorResponse)
-						return
+						isAuthorized = (node.Network == params["network"])
 					}
-					isAuthorized = (node.Network == params["network"])
 				case "node":
-					isAuthorized = (macaddress == params["macaddress"])
-				case "master":
-					isAuthorized = (macaddress == "mastermac")
+					if isnetadmin {
+						isAuthorized = true
+					} else {
+						isAuthorized = (macaddress == params["macaddress"])
+					}
+				case "user":
+					isAuthorized = true
 				default:
 					isAuthorized = false
 				}
@@ -239,6 +247,10 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 				return
 			} else {
 				//If authorized, this function passes along it's request and output to the appropriate route function.
+				if username == "" {
+					username = "(user not found)"
+				}
+				r.Header.Set("user", username)
 				next.ServeHTTP(w, r)
 			}
 		}
@@ -252,45 +264,38 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 
 	var nodes []models.Node
 	var params = mux.Vars(r)
-	nodes, err := GetNetworkNodes(params["network"])
+	networkName := params["network"]
+	nodes, err := GetNetworkNodes(networkName)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
 	//Returns all the nodes in JSON format
+	functions.PrintUserLog(r.Header.Get("user"), "fetched nodes on network"+networkName, 2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(nodes)
 }
 
 func GetNetworkNodes(network string) ([]models.Node, error) {
 	var nodes []models.Node
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"network": network}
-	//Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future
-	cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
-	if err != nil {
-		return []models.Node{}, err
-	}
-	defer cancel()
-	for cur.Next(context.TODO()) {
-		//Using a different model for the Node (other than regular node).
-		//Either we should do this for ALL structs (so Networks and Keys)
-		//OR we should just use the original struct
-		//My preference is to make some new return structs
-		//TODO: Think about this. Not an immediate concern. Just need to get some consistency eventually
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		if database.IsEmptyRecord(err) {
+			return []models.Node{}, nil
+		}
+		return nodes, err
+	}
+	for _, value := range collection {
+
 		var node models.Node
-		err := cur.Decode(&node)
+		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
-			return []models.Node{}, err
+			continue
+		}
+		if node.Network == network {
+			nodes = append(nodes, node)
 		}
-		// add item our array of nodes
-		nodes = append(nodes, node)
-	}
-	//TODO: Another fatal error we should take care of.
-	if err := cur.Err(); err != nil {
-		return []models.Node{}, err
 	}
 	return nodes, nil
 }
@@ -299,70 +304,42 @@ func GetNetworkNodes(network string) ([]models.Node, error) {
 //Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
 func getAllNodes(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
-	nodes, err := functions.GetAllNodes()
-	if err != nil {
+	user, err := functions.GetUser(r.Header.Get("user"))
+	if err != nil && r.Header.Get("ismasterkey") != "yes" {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	var nodes []models.Node
+	if user.IsAdmin || r.Header.Get("ismasterkey") == "yes" {
+		nodes, err = models.GetAllNodes()
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	} else {
+		nodes, err = getUsersNodes(user)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	}
 	//Return all the nodes in JSON format
+	functions.PrintUserLog(r.Header.Get("user"), "fetched nodes", 2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(nodes)
 }
 
-//This function get's called when a node "checks in" at check in interval
-//Honestly I'm not sure what all it should be doing
-//TODO: Implement the necessary stuff, including the below
-//Check the last modified of the network
-//Check the last modified of the nodes
-//Write functions for responding to these two thingies
-func checkIn(w http.ResponseWriter, r *http.Request) {
-
-	//TODO: Current thoughts:
-	//Dont bother with a networklastmodified
-	//Instead, implement a "configupdate" boolean on nodes
-	//when there is a network update  that requrires  a config update,  then the node will pull its new config
-
-	// set header.
-	w.Header().Set("Content-Type", "application/json")
-
-	var params = mux.Vars(r)
-	node, err := CheckIn(params["network"], params["macaddress"])
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(node)
-}
-func CheckIn(network, macaddress string) (models.Node, error) {
-	var node models.Node
-
-	//Retrieves node with DB Call which is inefficient. Let's just get the time and set it.
-	//node = functions.GetNodeByMacAddress(params["network"], params["macaddress"])
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"macaddress": macaddress, "network": network}
-	//old code was inefficient, this is all we need.
-	time := time.Now().Unix()
-	//node.SetLastCheckIn()
-	// prepare update model with new time
-	update := bson.D{
-		{"$set", bson.D{
-			{"lastcheckin", time},
-		}},
-	}
-	err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&node)
-	defer cancel()
-	if err != nil {
-		return models.Node{}, err
-	}
-	//TODO: check node last modified vs network last modified
-	//Get Updated node to return
-	node, err = GetNode(macaddress, network)
-	if err != nil {
-		return models.Node{}, err
+func getUsersNodes(user models.User) ([]models.Node, error) {
+	var nodes []models.Node
+	var err error
+	for _, networkName := range user.Networks {
+		tmpNodes, err := GetNetworkNodes(networkName)
+		if err != nil {
+			continue
+		}
+		nodes = append(nodes, tmpNodes...)
 	}
-	return node, nil
+	return nodes, err
 }
 
 //Get an individual node. Nothin fancy here folks.
@@ -377,6 +354,7 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "fetched node "+params["macaddress"], 2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 }
@@ -390,32 +368,16 @@ func getLastModified(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
 	var params = mux.Vars(r)
-	network, err := GetLastModified(params["network"])
+	network, err := GetNetwork(params["network"])
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "called last modified", 2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(network.NodesLastModified)
 }
 
-func GetLastModified(network string) (models.Network, error) {
-	var net models.Network
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": network}
-	err := collection.FindOne(ctx, filter).Decode(&net)
-	defer cancel()
-	if err != nil {
-		fmt.Println(err)
-		return models.Network{}, err
-	}
-	return net, nil
-}
-
-//This one's a doozy
-//To create a node
-//Must have valid key and be unique
 func createNode(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -424,12 +386,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	var errorResponse = models.ErrorResponse{
 		Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
 	}
-
 	networkName := params["network"]
-
-	//Check if network exists  first
-	//TODO: This is inefficient. Let's find a better way.
-	//Just a few rows down we grab the network anyway
 	networkexists, err := functions.NetworkExists(networkName)
 
 	if err != nil {
@@ -467,8 +424,8 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	if !validKey {
 		//Check to see if network will allow manual sign up
 		//may want to switch this up with the valid key check and avoid a DB call that way.
-		if *network.AllowManualSignUp {
-			node.IsPending = true
+		if network.AllowManualSignUp == "yes" {
+			node.IsPending = "yes"
 		} else {
 			errorResponse = models.ErrorResponse{
 				Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
@@ -478,17 +435,12 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
-	err = ValidateNodeCreate(networkName, node)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-
 	node, err = CreateNode(node, networkName)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "created new node "+node.Name+" on network "+node.Network, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 }
@@ -503,7 +455,7 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	fmt.Println("Node " + node.Name + " uncordoned.")
+	functions.PrintUserLog(r.Header.Get("user"), "uncordoned node "+node.Name, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode("SUCCESS")
 }
@@ -513,24 +465,20 @@ func UncordonNode(network, macaddress string) (models.Node, error) {
 	if err != nil {
 		return models.Node{}, err
 	}
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": macaddress, "network": network}
 	node.SetLastModified()
-	fmt.Println("Uncordoning node " + node.Name)
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"ispending", false},
-		}},
+	node.IsPending = "no"
+	node.PullChanges = "yes"
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return node, err
 	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&node)
-	defer cancel()
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
-		return models.Node{}, err
+		return node, err
 	}
-	return node, nil
+
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
+	return node, err
 }
 
 func createEgressGateway(w http.ResponseWriter, r *http.Request) {
@@ -549,6 +497,7 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "created egress gateway on node "+gateway.NodeID+" on network "+gateway.NetID, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 }
@@ -562,59 +511,42 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 	if err != nil {
 		return models.Node{}, err
 	}
-	var nodechange models.Node
-	nodechange.IsEgressGateway = true
-	nodechange.EgressGatewayRange = gateway.RangeString
-	nodechange.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
-	nodechange.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+	node.IsEgressGateway = "yes"
+	node.EgressGatewayRanges = gateway.Ranges
+	postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+	postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
 	if gateway.PostUp != "" {
-		nodechange.PostUp = gateway.PostUp
+		postUpCmd = gateway.PostUp
 	}
 	if gateway.PostDown != "" {
-		nodechange.PostDown = gateway.PostDown
+		postDownCmd = gateway.PostDown
 	}
 	if node.PostUp != "" {
-		if !strings.Contains(node.PostUp, nodechange.PostUp) {
-			nodechange.PostUp = node.PostUp + "; " + nodechange.PostUp
-		} else {
-			nodechange.PostUp = node.PostUp
+		if !strings.Contains(node.PostUp, postUpCmd) {
+			postUpCmd = node.PostUp + "; " + postUpCmd
 		}
 	}
-        if node.PostDown != "" {
-                if !strings.Contains(node.PostDown, nodechange.PostDown) {
-                        nodechange.PostDown = node.PostDown + "; " + nodechange.PostDown
-                } else {
-                        nodechange.PostDown = node.PostDown
-                }
-        }
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": gateway.NodeID, "network": gateway.NetID}
-	nodechange.SetLastModified()
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"postup", nodechange.PostUp},
-			{"postdown", nodechange.PostDown},
-			{"isegressgateway", nodechange.IsEgressGateway},
-			{"egressgatewayrange", nodechange.EgressGatewayRange},
-			{"lastmodified", nodechange.LastModified},
-		}},
-	}
-	var nodeupdate models.Node
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
+	if node.PostDown != "" {
+		if !strings.Contains(node.PostDown, postDownCmd) {
+			postDownCmd = node.PostDown + "; " + postDownCmd
+		}
+	}
+	key, err := functions.GetRecordKey(gateway.NodeID, gateway.NetID)
 	if err != nil {
-		return models.Node{}, err
+		return node, err
 	}
-	err = SetNetworkNodesLastModified(gateway.NetID)
+	node.PostUp = postUpCmd
+	node.PostDown = postDownCmd
+	node.SetLastModified()
+	node.PullChanges = "yes"
+	nodeData, err := json.Marshal(&node)
 	if err != nil {
+		return node, err
+	}
+	if err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME); err != nil {
 		return models.Node{}, err
 	}
-	//Get updated values to return
-	node, err = functions.GetNodeByMacAddress(gateway.NetID, gateway.NodeID)
-	if err != nil {
+	if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
 		return models.Node{}, err
 	}
 	return node, nil
@@ -622,10 +554,10 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 
 func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
 	var err error
-	isIp := functions.IsIpCIDR(gateway.RangeString)
-	empty := gateway.RangeString == ""
-	if empty || !isIp {
-		err = errors.New("IP Range Not Valid")
+	//isIp := functions.IsIpCIDR(gateway.RangeString)
+	empty := len(gateway.Ranges) == 0
+	if empty {
+		err = errors.New("IP Ranges Cannot Be Empty")
 	}
 	empty = gateway.Interface == ""
 	if empty {
@@ -637,69 +569,60 @@ func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
 func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
-	node, err := DeleteEgressGateway(params["network"], params["macaddress"])
+	nodeMac := params["macaddress"]
+	netid := params["network"]
+	node, err := DeleteEgressGateway(netid, nodeMac)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 }
 
 func DeleteEgressGateway(network, macaddress string) (models.Node, error) {
 
-	var nodeupdate models.Node
-	var nodechange models.Node
 	node, err := functions.GetNodeByMacAddress(network, macaddress)
 	if err != nil {
 		return models.Node{}, err
 	}
 
-	nodechange.IsEgressGateway = false
-	nodechange.EgressGatewayRange = ""
-	nodechange.PostUp = ""
-	nodechange.PostDown = ""
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": macaddress, "network": network}
-	nodechange.SetLastModified()
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"postup", nodechange.PostUp},
-			{"postdown", nodechange.PostDown},
-			{"isegressgateway", nodechange.IsEgressGateway},
-			{"egressgatewayrange", nodechange.EgressGatewayRange},
-			{"lastmodified", nodechange.LastModified},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
+	node.IsEgressGateway = "no"
+	node.EgressGatewayRanges = []string{}
+	node.PostUp = ""
+	node.PostDown = ""
+	node.SetLastModified()
+	node.PullChanges = "yes"
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 		return models.Node{}, err
 	}
-	err = SetNetworkNodesLastModified(network)
+	data, err := json.Marshal(&node)
 	if err != nil {
 		return models.Node{}, err
 	}
-	//Get updated values to return
-	node, err = functions.GetNodeByMacAddress(network, macaddress)
-	if err != nil {
+	if err = database.Insert(key, string(data), database.NODES_TABLE_NAME); err != nil {
+		return models.Node{}, err
+	}
+	if err = functions.NetworkNodesUpdatePullChanges(network); err != nil {
 		return models.Node{}, err
 	}
 	return node, nil
 }
+
 // == INGRESS ==
 func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
-	node, err := CreateIngressGateway(params["network"], params["macaddress"])
+	nodeMac := params["macaddress"]
+	netid := params["network"]
+	node, err := CreateIngressGateway(netid, nodeMac)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "created ingress gateway on node "+nodeMac+" on network "+netid, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 }
@@ -707,115 +630,98 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 func CreateIngressGateway(netid string, macaddress string) (models.Node, error) {
 
 	node, err := functions.GetNodeByMacAddress(netid, macaddress)
-        if err != nil {
-                return models.Node{}, err
-        }
-
-        network, err := functions.GetParentNetwork(netid)
-        if err != nil {
-		log.Println("Could not find network.")
-                return models.Node{}, err
-        }
-        var nodechange models.Node
-	nodechange.IngressGatewayRange = network.AddressRange
-        nodechange.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
-        nodechange.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
-        if node.PostUp != "" {
-                if !strings.Contains(node.PostUp, nodechange.PostUp) {
-                        nodechange.PostUp = node.PostUp + "; " + nodechange.PostUp
-                } else {
-                        nodechange.PostUp = node.PostUp
-                }
-        }
-        if node.PostDown != "" {
-                if !strings.Contains(node.PostDown, nodechange.PostDown) {
-                        nodechange.PostDown = node.PostDown + "; " + nodechange.PostDown
-                } else {
-                        nodechange.PostDown = node.PostDown
-                }
-        }
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-        // Create filter
-        filter := bson.M{"macaddress": macaddress, "network": netid}
-        node.SetLastModified()
-        // prepare update model.
-        update := bson.D{
-                {"$set", bson.D{
-                        {"postup", nodechange.PostUp},
-                        {"postdown", nodechange.PostDown},
-                        {"isingressgateway", true},
-                        {"ingressgatewayrange", nodechange.IngressGatewayRange},
-                        {"lastmodified", node.LastModified},
-                }},
-        }
-        var nodeupdate models.Node
-        err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-        defer cancel()
-        if err != nil {
-		log.Println("error updating node to gateway")
-                return models.Node{}, err
-        }
-        err = SetNetworkNodesLastModified(netid)
-        if err != nil {
-                return node, err
-        }
-        //Get updated values to return
-        node, err = functions.GetNodeByMacAddress(netid, macaddress)
-        if err != nil {
-		log.Println("error finding node after update")
-                return node, err
-        }
-        return node, nil
+	if err != nil {
+		return models.Node{}, err
+	}
+
+	network, err := functions.GetParentNetwork(netid)
+	if err != nil {
+		return models.Node{}, err
+	}
+	node.IsIngressGateway = "yes"
+	node.IngressGatewayRange = network.AddressRange
+	postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
+	postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
+	if node.PostUp != "" {
+		if !strings.Contains(node.PostUp, postUpCmd) {
+			postUpCmd = node.PostUp + "; " + postUpCmd
+		}
+	}
+	if node.PostDown != "" {
+		if !strings.Contains(node.PostDown, postDownCmd) {
+			postDownCmd = node.PostDown + "; " + postDownCmd
+		}
+	}
+	node.SetLastModified()
+	node.PostUp = postUpCmd
+	node.PostDown = postDownCmd
+	node.PullChanges = "yes"
+	node.UDPHolePunch = "no"
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return models.Node{}, err
+	}
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = SetNetworkNodesLastModified(netid)
+	return node, err
 }
 
 func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
-	node, err := DeleteIngressGateway(params["network"], params["macaddress"])
+	nodeMac := params["macaddress"]
+	node, err := DeleteIngressGateway(params["network"], nodeMac)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "deleted ingress gateway"+nodeMac, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 }
 
-func DeleteIngressGateway(network, macaddress string) (models.Node, error) {
+func DeleteIngressGateway(networkName string, macaddress string) (models.Node, error) {
 
-	var nodeupdate models.Node
-	node, err := functions.GetNodeByMacAddress(network, macaddress)
+	node, err := functions.GetNodeByMacAddress(networkName, macaddress)
 	if err != nil {
 		return models.Node{}, err
 	}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": macaddress, "network": network}
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"lastmodified", time.Now().Unix()},
-			{"isingressgateway", false},
-		}},
+	network, err := functions.GetParentNetwork(networkName)
+	if err != nil {
+		return models.Node{}, err
+	}
+	// delete ext clients belonging to ingress gateway
+	if err = DeleteGatewayExtClients(macaddress, networkName); err != nil {
+		return models.Node{}, err
 	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
+
+	node.UDPHolePunch = network.DefaultUDPHolePunch
+	node.LastModified = time.Now().Unix()
+	node.IsIngressGateway = "no"
+	node.IngressGatewayRange = ""
+	node.PullChanges = "yes"
+
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 		return models.Node{}, err
 	}
-	err = SetNetworkNodesLastModified(network)
+	data, err := json.Marshal(&node)
 	if err != nil {
 		return models.Node{}, err
 	}
-	//Get updated values to return
-	node, err = functions.GetNodeByMacAddress(network, macaddress)
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
 	if err != nil {
 		return models.Node{}, err
 	}
-	return node, nil
+	err = SetNetworkNodesLastModified(networkName)
+	return node, err
 }
 
 func updateNode(w http.ResponseWriter, r *http.Request) {
@@ -823,11 +729,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
 
-	//Get id from parameters
-	//id, _ := primitive.ObjectIDFromHex(params["id"])
-
 	var node models.Node
-
 	//start here
 	node, err := functions.GetNodeByMacAddress(params["network"], params["macaddress"])
 	if err != nil {
@@ -835,29 +737,30 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	var nodechange models.NodeUpdate
-
+	var newNode models.Node
 	// we decode our body request params
-	_ = json.NewDecoder(r.Body).Decode(&nodechange)
-	if nodechange.Network == "" {
-		nodechange.Network = node.Network
-	}
-	if nodechange.MacAddress == "" {
-		nodechange.MacAddress = node.MacAddress
-	}
-	err = ValidateNodeUpdate(params["network"], nodechange)
+	err = json.NewDecoder(r.Body).Decode(&newNode)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	newNode.PullChanges = "yes"
+	err = node.Update(&newNode)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 
-	node, err = UpdateNode(nodechange, node)
+	if servercfg.IsDNSMode() {
+		err = SetDNS()
+	}
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "updated node "+node.MacAddress+" on network "+node.Network, 1)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(node)
+	json.NewEncoder(w).Encode(newNode)
 }
 
 //Delete a node
@@ -869,15 +772,12 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 	// get params
 	var params = mux.Vars(r)
 
-	success, err := DeleteNode(params["macaddress"], params["network"])
+	err := DeleteNode(params["macaddress"]+"###"+params["network"], false)
 
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
-	} else if !success {
-		err = errors.New("Could not delete node " + params["macaddress"])
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "Deleted node "+params["macaddress"]+" from network "+params["network"], 1)
 	returnSuccessResponse(w, r, params["macaddress"]+" deleted.")
 }

+ 7 - 14
controllers/nodeHttpController_test.go

@@ -34,7 +34,7 @@ func TestCheckIn(t *testing.T) {
 func TestCreateEgressGateway(t *testing.T) {
 	var gateway models.EgressGatewayRequest
 	gateway.Interface = "eth0"
-	gateway.RangeString = "10.100.100.0/24"
+	gateway.Ranges = []string{"10.100.100.0/24"}
 	deleteNet(t)
 	createNet()
 	t.Run("NoNodes", func(t *testing.T) {
@@ -62,18 +62,18 @@ func TestDeleteEgressGateway(t *testing.T) {
 	createTestNode(t)
 	testnode := createTestNode(t)
 	gateway.Interface = "eth0"
-	gateway.RangeString = "10.100.100.0/24"
+	gateway.Ranges = []string{"10.100.100.0/24"}
 	gateway.NetID = "skynet"
 	gateway.NodeID = testnode.MacAddress
 	t.Run("Success", func(t *testing.T) {
 		node, err := CreateEgressGateway(gateway)
 		assert.Nil(t, err)
 		assert.Equal(t, true, node.IsEgressGateway)
-		assert.Equal(t, "10.100.100.0/24", node.EgressGatewayRange)
+		assert.Equal(t, []string{"10.100.100.0/24"}, node.EgressGatewayRanges)
 		node, err = DeleteEgressGateway(gateway.NetID, gateway.NodeID)
 		assert.Nil(t, err)
 		assert.Equal(t, false, node.IsEgressGateway)
-		assert.Equal(t, "", node.EgressGatewayRange)
+		assert.Equal(t, "", node.EgressGatewayRanges)
 		assert.Equal(t, "", node.PostUp)
 		assert.Equal(t, "", node.PostDown)
 	})
@@ -81,7 +81,7 @@ func TestDeleteEgressGateway(t *testing.T) {
 		node, err := DeleteEgressGateway(gateway.NetID, gateway.NodeID)
 		assert.Nil(t, err)
 		assert.Equal(t, false, node.IsEgressGateway)
-		assert.Equal(t, "", node.EgressGatewayRange)
+		assert.Equal(t, "", node.EgressGatewayRanges)
 		assert.Equal(t, "", node.PostUp)
 		assert.Equal(t, "", node.PostDown)
 	})
@@ -162,16 +162,9 @@ func TestUncordonNode(t *testing.T) {
 }
 func TestValidateEgressGateway(t *testing.T) {
 	var gateway models.EgressGatewayRequest
-	t.Run("InvalidRange", func(t *testing.T) {
-		gateway.Interface = "eth0"
-		gateway.RangeString = "helloworld"
-		err := ValidateEgressGateway(gateway)
-		assert.NotNil(t, err)
-		assert.Equal(t, "IP Range Not Valid", err.Error())
-	})
 	t.Run("EmptyRange", func(t *testing.T) {
 		gateway.Interface = "eth0"
-		gateway.RangeString = ""
+		gateway.Ranges = []string{}
 		err := ValidateEgressGateway(gateway)
 		assert.NotNil(t, err)
 		assert.Equal(t, "IP Range Not Valid", err.Error())
@@ -184,7 +177,7 @@ func TestValidateEgressGateway(t *testing.T) {
 	})
 	t.Run("Success", func(t *testing.T) {
 		gateway.Interface = "eth0"
-		gateway.RangeString = "10.100.100.0/24"
+		gateway.Ranges = []string{"10.100.100.0/24"}
 		err := ValidateEgressGateway(gateway)
 		assert.Nil(t, err)
 	})

+ 13 - 24
controllers/serverHttpController.go

@@ -12,16 +12,15 @@ import (
 )
 
 func serverHandlers(r *mux.Router) {
-    r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(http.HandlerFunc(addNetwork))).Methods("POST")
-    r.HandleFunc("/api/server/getconfig", securityCheckServer(http.HandlerFunc(getConfig))).Methods("GET")
-    r.HandleFunc("/api/server/getwgconfig", securityCheckServer(http.HandlerFunc(getWGConfig))).Methods("GET")
-    r.HandleFunc("/api/server/removenetwork/{network}", securityCheckServer(http.HandlerFunc(removeNetwork))).Methods("DELETE")
+    r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(true, http.HandlerFunc(addNetwork))).Methods("POST")
+    r.HandleFunc("/api/server/getconfig", securityCheckServer(false, http.HandlerFunc(getConfig))).Methods("GET")
+    r.HandleFunc("/api/server/removenetwork/{network}", securityCheckServer(true, http.HandlerFunc(removeNetwork))).Methods("DELETE")
 }
 
 //Security check is middleware for every function and just checks to make sure that its the master calling
 //Only admin should have access to all these network-level actions
 //or maybe some Users once implemented
-func securityCheckServer(next http.Handler) http.HandlerFunc {
+func securityCheckServer(adminonly bool, next http.Handler) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var errorResponse = models.ErrorResponse{
 			Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
@@ -42,15 +41,16 @@ func securityCheckServer(next http.Handler) http.HandlerFunc {
 		}
 		//all endpoints here require master so not as complicated
 		//still might not be a good  way of doing this
-                _, isadmin, _ := functions.VerifyUserToken(authToken)
-
+                user, _, isadmin, err := functions.VerifyUserToken(authToken)
+                errorResponse = models.ErrorResponse{
+                        Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
+                }
+                if !adminonly && (err != nil || user == "") {
+                        returnErrorResponse(w, r, errorResponse)
+                }
 		if !isadmin && !authenticateMasterServer(authToken) {
-				errorResponse = models.ErrorResponse{
-					Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
-				}
-				returnErrorResponse(w, r, errorResponse)
-				return
-		}
+                        returnErrorResponse(w, r, errorResponse)
+                }
 		next.ServeHTTP(w, r)
 	}
 }
@@ -90,17 +90,6 @@ func getConfig(w http.ResponseWriter, r *http.Request) {
         json.NewEncoder(w).Encode(scfg)
 }
 
-func getWGConfig(w http.ResponseWriter, r *http.Request) {
-        // Set header
-        w.Header().Set("Content-Type", "application/json")
-
-        // get params
-
-        wgcfg := servercfg.GetWGConfig()
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(wgcfg)
-}
-
 /*
 func getMongoConfig(w http.ResponseWriter, r *http.Request) {
         // Set header

+ 208 - 123
controllers/userHttpController.go

@@ -1,22 +1,17 @@
 package controller
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"net/http"
 	"strings"
-	"time"
 
 	"github.com/go-playground/validator/v10"
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo"
-	"go.mongodb.org/mongo-driver/mongo/options"
 	"golang.org/x/crypto/bcrypt"
 )
 
@@ -26,8 +21,11 @@ func userHandlers(r *mux.Router) {
 	r.HandleFunc("/api/users/adm/createadmin", createAdmin).Methods("POST")
 	r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods("POST")
 	r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(updateUser))).Methods("PUT")
+	r.HandleFunc("/api/users/{username}/adm", authorizeUserAdm(http.HandlerFunc(updateUserAdm))).Methods("PUT")
+	r.HandleFunc("/api/users/{username}", authorizeUserAdm(http.HandlerFunc(createUser))).Methods("POST")
 	r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(deleteUser))).Methods("DELETE")
 	r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(getUser))).Methods("GET")
+	r.HandleFunc("/api/users", authorizeUserAdm(http.HandlerFunc(getUsers))).Methods("GET")
 }
 
 //Node authenticates using its password and retrieves a JWT for authorization.
@@ -60,12 +58,13 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 		return
 	}
 
+	username := authRequest.UserName
 	var successResponse = models.SuccessResponse{
 		Code:    http.StatusOK,
-		Message: "W1R3: Device " + authRequest.UserName + " Authorized",
+		Message: "W1R3: Device " + username + " Authorized",
 		Response: models.SuccessfulUserLoginResponse{
 			AuthToken: jwt,
-			UserName:  authRequest.UserName,
+			UserName:  username,
 		},
 	}
 	//Send back the JWT
@@ -75,6 +74,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 		returnErrorResponse(response, request, errorResponse)
 		return
 	}
+	functions.PrintUserLog(username, "was authenticated", 2)
 	response.Header().Set("Content-Type", "application/json")
 	response.Write(successJSONResponse)
 }
@@ -82,34 +82,28 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 func VerifyAuthRequest(authRequest models.UserAuthParams) (string, error) {
 	var result models.User
 	if authRequest.UserName == "" {
-		return "", errors.New("Username can't be empty")
+		return "", errors.New("username can't be empty")
 	} else if authRequest.Password == "" {
-		return "", errors.New("Password can't be empty")
+		return "", errors.New("password can't be empty")
 	}
 	//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	var err = collection.FindOne(ctx, bson.M{"username": authRequest.UserName}).Decode(&result)
-
-	defer cancel()
+	record, err := database.FetchRecord(database.USERS_TABLE_NAME, authRequest.UserName)
 	if err != nil {
-		return "", errors.New("User " + authRequest.UserName + " not found")
+		return "", errors.New("user " + authRequest.UserName + " not found")
 	}
-	// This is a a useless test as cannot create user that is not an an admin
-	if !result.IsAdmin {
-		return "", errors.New("User is not an admin")
+	if err = json.Unmarshal([]byte(record), &result); err != nil {
+		return "", errors.New("user " + authRequest.UserName + " not found")
 	}
 
 	//compare password from request to stored password in database
 	//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
 	//TODO: Consider a way of hashing the password client side before sending, or using certificates
-	err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password))
-	if err != nil {
-		return "", errors.New("Wrong Password")
+	if err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password)); err != nil {
+		return "", errors.New("wrong password")
 	}
 
 	//Create a new JWT for the node
-	tokenString, _ := functions.CreateUserJWT(authRequest.UserName, true)
+	tokenString, _ := functions.CreateUserJWT(authRequest.UserName, result.Networks, result.IsAdmin)
 	return tokenString, nil
 }
 
@@ -123,21 +117,41 @@ func VerifyAuthRequest(authRequest models.UserAuthParams) (string, error) {
 func authorizeUser(next http.Handler) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		w.Header().Set("Content-Type", "application/json")
+		var params = mux.Vars(r)
 
 		//get the auth token
 		bearerToken := r.Header.Get("Authorization")
-		err := ValidateUserToken(bearerToken)
+		username := params["username"]
+		err := ValidateUserToken(bearerToken, username, false)
 		if err != nil {
 			returnErrorResponse(w, r, formatError(err, "unauthorized"))
 			return
 		}
+		r.Header.Set("user", username)
 		next.ServeHTTP(w, r)
 	}
 }
 
-func ValidateUserToken(token string) error {
-	var tokenSplit = strings.Split(token, " ")
+func authorizeUserAdm(next http.Handler) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		var params = mux.Vars(r)
+
+		//get the auth token
+		bearerToken := r.Header.Get("Authorization")
+		username := params["username"]
+		err := ValidateUserToken(bearerToken, username, true)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "unauthorized"))
+			return
+		}
+		r.Header.Set("user", username)
+		next.ServeHTTP(w, r)
+	}
+}
 
+func ValidateUserToken(token string, user string, adminonly bool) error {
+	var tokenSplit = strings.Split(token, " ")
 	//I put this in in case the user doesn't put in a token at all (in which case it's empty)
 	//There's probably a smarter way of handling this.
 	var authToken = "928rt238tghgwe@TY@$Y@#WQAEGB2FC#@HG#@$Hddd"
@@ -148,12 +162,16 @@ func ValidateUserToken(token string) error {
 		return errors.New("Missing Auth Token.")
 	}
 
-	username, _, err := functions.VerifyUserToken(authToken)
+	username, _, isadmin, err := functions.VerifyUserToken(authToken)
 	if err != nil {
 		return errors.New("Error Verifying Auth Token")
 	}
-
-	isAuthorized := username != ""
+	isAuthorized := false
+	if adminonly {
+		isAuthorized = isadmin
+	} else {
+		isAuthorized = username == user || isadmin
+	}
 	if !isAuthorized {
 		return errors.New("You are unauthorized to access this endpoint.")
 	}
@@ -163,55 +181,90 @@ func ValidateUserToken(token string) error {
 
 func HasAdmin() (bool, error) {
 
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"isadmin": true}
-
-	//Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future
-	var result bson.M
-
-	err := collection.FindOne(ctx, filter).Decode(&result)
-
-	defer cancel()
-
+	collection, err := database.FetchRecords(database.USERS_TABLE_NAME)
 	if err != nil {
-		if err == mongo.ErrNoDocuments {
+		if database.IsEmptyRecord(err) {
 			return false, nil
+		} else {
+			return true, err
+	
 		}
-		return false, err
-		fmt.Println(err)
 	}
-	return true, err
+	for _, value := range collection { // filter for isadmin true
+		var user models.User
+		err = json.Unmarshal([]byte(value), &user)
+		if err != nil {
+			continue
+		}
+		if user.IsAdmin {
+			return true, nil
+		}
+	}
+
+	return false, err
 }
 
 func hasAdmin(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
 
-	hasadmin, _ := HasAdmin()
-
-	//Returns all the nodes in JSON format
+	hasadmin, err := HasAdmin()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}	
 
 	json.NewEncoder(w).Encode(hasadmin)
 
 }
 
-func GetUser(username string) (models.User, error) {
+func GetUser(username string) (models.ReturnUser, error) {
+
+	var user models.ReturnUser
+	record, err := database.FetchRecord(database.USERS_TABLE_NAME, username)
+	if err != nil {
+		return user, err
+	}
+	if err = json.Unmarshal([]byte(record), &user); err != nil {
+		return models.ReturnUser{}, err
+	}
+	return user, err
+}
+
+func GetUserInternal(username string) (models.User, error) {
 
 	var user models.User
+	record, err := database.FetchRecord(database.USERS_TABLE_NAME, username)
+	if err != nil {
+		return user, err
+	}
+	if err = json.Unmarshal([]byte(record), &user); err != nil {
+		return models.User{}, err
+	}
+	return user, err
+}
 
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
+func GetUsers() ([]models.ReturnUser, error) {
 
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	var users []models.ReturnUser
 
-	filter := bson.M{"username": username}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&user)
+	collection, err := database.FetchRecords(database.USERS_TABLE_NAME)
 
-	defer cancel()
+	if err != nil {
+		return users, err
+	}
 
-	return user, err
+	for _, value := range collection {
+
+		var user models.ReturnUser
+		err = json.Unmarshal([]byte(value), &user)
+		if err != nil {
+			continue // get users
+		}
+		users = append(users, user)
+	}
+
+	return users, err
 }
 
 //Get an individual node. Nothin fancy here folks.
@@ -220,25 +273,35 @@ func getUser(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
 	var params = mux.Vars(r)
-
-	user, err := GetUser(params["username"])
+	usernameFetched := params["username"]
+	user, err := GetUser(usernameFetched)
 
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
+	functions.PrintUserLog(r.Header.Get("user"), "fetched user "+usernameFetched, 2)
 	json.NewEncoder(w).Encode(user)
 }
 
-func CreateUser(user models.User) (models.User, error) {
-	hasadmin, err := HasAdmin()
-	if hasadmin {
-		return models.User{}, errors.New("Admin already Exists")
+//Get an individual node. Nothin fancy here folks.
+func getUsers(w http.ResponseWriter, r *http.Request) {
+	// set header.
+	w.Header().Set("Content-Type", "application/json")
+
+	users, err := GetUsers()
+
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
 	}
 
-	user.IsAdmin = true
-	err = ValidateUser("create", user)
+	functions.PrintUserLog(r.Header.Get("user"), "fetched users", 2)
+	json.NewEncoder(w).Encode(users)
+}
+
+func CreateUser(user models.User) (models.User, error) {
+	err := ValidateUser("create", user)
 	if err != nil {
 		return models.User{}, err
 	}
@@ -251,7 +314,7 @@ func CreateUser(user models.User) (models.User, error) {
 	//set password to encrypted password
 	user.Password = string(hash)
 
-	tokenString, _ := functions.CreateUserJWT(user.UserName, user.IsAdmin)
+	tokenString, _ := functions.CreateUserJWT(user.UserName, user.Networks, user.IsAdmin)
 
 	if tokenString == "" {
 		//returnErrorResponse(w, r, errorResponse)
@@ -259,12 +322,11 @@ func CreateUser(user models.User) (models.User, error) {
 	}
 
 	// connect db
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// insert our node to the node db.
-	_, err = collection.InsertOne(ctx, user)
-	defer cancel()
+	data, err := json.Marshal(&user)
+	if err != nil {
+		return user, err
+	}
+	err = database.Insert(user.UserName, string(data), database.USERS_TABLE_NAME)
 
 	return user, err
 }
@@ -275,17 +337,34 @@ func createAdmin(w http.ResponseWriter, r *http.Request) {
 	var admin models.User
 	//get node from body of request
 	_ = json.NewDecoder(r.Body).Decode(&admin)
-
+	admin.IsAdmin = true
 	admin, err := CreateUser(admin)
 
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
-
+	functions.PrintUserLog(admin.UserName, "was made a new admin", 1)
 	json.NewEncoder(w).Encode(admin)
 }
 
+func createUser(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+
+	var user models.User
+	//get node from body of request
+	_ = json.NewDecoder(r.Body).Decode(&user)
+
+	user, err := CreateUser(user)
+
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+	functions.PrintUserLog(user.UserName, "was created", 1)
+	json.NewEncoder(w).Encode(user)
+}
+
 func UpdateUser(userchange models.User, user models.User) (models.User, error) {
 
 	err := ValidateUser("update", userchange)
@@ -298,6 +377,9 @@ func UpdateUser(userchange models.User, user models.User) (models.User, error) {
 	if userchange.UserName != "" {
 		user.UserName = userchange.UserName
 	}
+	if len(userchange.Networks) > 0 {
+		user.Networks = userchange.Networks
+	}
 	if userchange.Password != "" {
 		//encrypt that password so we never see it again
 		hash, err := bcrypt.GenerateFromPassword([]byte(userchange.Password), 5)
@@ -310,37 +392,18 @@ func UpdateUser(userchange models.User, user models.User) (models.User, error) {
 
 		user.Password = userchange.Password
 	}
-	//collection := mongoconn.ConnectDB()
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"username": queryUser}
-
-	fmt.Println("Updating User " + user.UserName)
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"username", user.UserName},
-			{"password", user.Password},
-			{"isadmin", user.IsAdmin},
-		}},
+	if err = database.DeleteRecord(database.USERS_TABLE_NAME, queryUser); err != nil {
+		return models.User{}, err
 	}
-	var userupdate models.User
-
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&userupdate)
-	if errN != nil {
-		fmt.Println("Could not update: ")
-		fmt.Println(errN)
-	} else {
-		fmt.Println("User updated  successfully.")
+	data, err := json.Marshal(&user)
+	if err != nil {
+		return models.User{}, err
 	}
-
-	defer cancel()
-
-	return user, errN
+	if err = database.Insert(user.UserName, string(data), database.USERS_TABLE_NAME); err != nil {
+		return models.User{}, err
+	}
+	functions.PrintUserLog(models.NODE_SERVER_NAME, "updated user "+queryUser, 1)
+	return user, nil
 }
 
 func updateUser(w http.ResponseWriter, r *http.Request) {
@@ -348,7 +411,8 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	var user models.User
 	//start here
-	user, err := GetUser(params["username"])
+	username := params["username"]
+	user, err := GetUserInternal(username)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -360,35 +424,54 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	userchange.Networks = nil
 	user, err = UpdateUser(userchange, user)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	functions.PrintUserLog(username, "was updated", 1)
 	json.NewEncoder(w).Encode(user)
 }
 
-func DeleteUser(user string) (bool, error) {
-
-	deleted := false
-
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-
-	filter := bson.M{"username": user}
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	result, err := collection.DeleteOne(ctx, filter)
+func updateUserAdm(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	var user models.User
+	//start here
+	username := params["username"]
+	user, err := GetUserInternal(username)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	var userchange models.User
+	// we decode our body request params
+	err = json.NewDecoder(r.Body).Decode(&userchange)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	user, err = UpdateUser(userchange, user)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+	functions.PrintUserLog(username, "was updated (admin)", 1)
+	json.NewEncoder(w).Encode(user)
+}
 
-	deletecount := result.DeletedCount
+func DeleteUser(user string) (bool, error) {
 
-	if deletecount > 0 {
-		deleted = true
+	if userRecord, err := database.FetchRecord(database.USERS_TABLE_NAME, user); err != nil || len(userRecord) == 0 {
+		return false, errors.New("user does not exist")
 	}
 
-	defer cancel()
-
-	return deleted, err
+	err := database.DeleteRecord(database.USERS_TABLE_NAME, user)
+	if err != nil {
+		return false, err
+	}
+	return true, nil
 }
 
 func deleteUser(w http.ResponseWriter, r *http.Request) {
@@ -398,16 +481,18 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 	// get params
 	var params = mux.Vars(r)
 
-	success, err := DeleteUser(params["username"])
+	username := params["username"]
+	success, err := DeleteUser(username)
 
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	} else if !success {
-		returnErrorResponse(w, r, formatError(errors.New("Delete unsuccessful."), "badrequest"))
+		returnErrorResponse(w, r, formatError(errors.New("delete unsuccessful."), "badrequest"))
 		return
 	}
 
+	functions.PrintUserLog(username, "was deleted", 1)
 	json.NewEncoder(w).Encode(params["username"] + " deleted.")
 }
 

+ 16 - 20
controllers/userHttpController_test.go

@@ -1,23 +1,19 @@
 package controller
 
 import (
-	"context"
-	"os"
 	"testing"
-	"time"
 
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/stretchr/testify/assert"
 )
 
-func TestMain(m *testing.M) {
-	mongoconn.ConnectDatabase()
+/*func TestMain(m *testing.M) {
+	database.InitializeDatabase()
 	var gconf models.GlobalConfig
 	gconf.ServerGRPC = "localhost:8081"
 	gconf.PortGRPC = "50051"
 	//err := SetGlobalConfig(gconf)
-	collection := mongoconn.Client.Database("netmaker").Collection("config")
+	collection := REMOVE.Client.Database(models.NODE_SERVER_NAME).Collection("config")
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	defer cancel()
 	//create, _, err := functions.GetGlobalConfig()
@@ -28,7 +24,7 @@ func TestMain(m *testing.M) {
 	//drop network, nodes, and user collections
 	var collections = []string{"networks", "nodes", "users", "dns"}
 	for _, table := range collections {
-		collection := mongoconn.Client.Database("netmaker").Collection(table)
+		collection := REMOVE.Client.Database(models.NODE_SERVER_NAME).Collection(table)
 		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 		defer cancel()
 		err := collection.Drop(ctx)
@@ -38,11 +34,11 @@ func TestMain(m *testing.M) {
 	}
 	os.Exit(m.Run())
 }
-
+*/
 func TestHasAdmin(t *testing.T) {
 	_, err := DeleteUser("admin")
 	assert.Nil(t, err)
-	user := models.User{"admin", "password", true}
+	user := models.User{"admin", "password", nil, true}
 	_, err = CreateUser(user)
 	assert.Nil(t, err)
 	t.Run("AdminExists", func(t *testing.T) {
@@ -60,7 +56,7 @@ func TestHasAdmin(t *testing.T) {
 }
 
 func TestCreateUser(t *testing.T) {
-	user := models.User{"admin", "password", true}
+	user := models.User{"admin", "password", nil, true}
 	t.Run("NoUser", func(t *testing.T) {
 		_, err := DeleteUser("admin")
 		assert.Nil(t, err)
@@ -79,7 +75,7 @@ func TestDeleteUser(t *testing.T) {
 	hasadmin, err := HasAdmin()
 	assert.Nil(t, err)
 	if !hasadmin {
-		user := models.User{"admin", "pasword", true}
+		user := models.User{"admin", "pasword", nil, true}
 		_, err := CreateUser(user)
 		assert.Nil(t, err)
 	}
@@ -138,7 +134,7 @@ func TestValidateUser(t *testing.T) {
 
 func TestGetUser(t *testing.T) {
 	t.Run("UserExisits", func(t *testing.T) {
-		user := models.User{"admin", "password", true}
+		user := models.User{"admin", "password", nil, true}
 		hasadmin, err := HasAdmin()
 		assert.Nil(t, err)
 		if !hasadmin {
@@ -159,8 +155,8 @@ func TestGetUser(t *testing.T) {
 }
 
 func TestUpdateUser(t *testing.T) {
-	user := models.User{"admin", "password", true}
-	newuser := models.User{"hello", "world", true}
+	user := models.User{"admin", "password", nil, true}
+	newuser := models.User{"hello", "world", nil, true}
 	t.Run("UserExisits", func(t *testing.T) {
 		_, err := DeleteUser("admin")
 		_, err = CreateUser(user)
@@ -179,12 +175,12 @@ func TestUpdateUser(t *testing.T) {
 
 func TestValidateUserToken(t *testing.T) {
 	t.Run("EmptyToken", func(t *testing.T) {
-		err := ValidateUserToken("")
+		err := ValidateUserToken("", "", false)
 		assert.NotNil(t, err)
 		assert.Equal(t, "Missing Auth Token.", err.Error())
 	})
 	t.Run("InvalidToken", func(t *testing.T) {
-		err := ValidateUserToken("Bearer: badtoken")
+		err := ValidateUserToken("Bearer: badtoken", "", false)
 		assert.NotNil(t, err)
 		assert.Equal(t, "Error Verifying Auth Token", err.Error())
 	})
@@ -193,7 +189,7 @@ func TestValidateUserToken(t *testing.T) {
 		//need authorization
 	})
 	t.Run("ValidToken", func(t *testing.T) {
-		err := ValidateUserToken("Bearer: secretkey")
+		err := ValidateUserToken("Bearer: secretkey", "", true)
 		assert.Nil(t, err)
 	})
 }
@@ -228,7 +224,7 @@ func TestVerifyAuthRequest(t *testing.T) {
 	t.Run("Non-Admin", func(t *testing.T) {
 		//can't create a user that is not a an admin
 		t.Skip()
-		user := models.User{"admin", "admin", false}
+		user := models.User{"admin", "admin", nil, false}
 		_, err := CreateUser(user)
 		assert.Nil(t, err)
 		authRequest := models.UserAuthParams{"admin", "admin"}
@@ -239,7 +235,7 @@ func TestVerifyAuthRequest(t *testing.T) {
 	})
 	t.Run("WrongPassword", func(t *testing.T) {
 		_, err := DeleteUser("admin")
-		user := models.User{"admin", "password", true}
+		user := models.User{"admin", "password", nil, true}
 		_, err = CreateUser(user)
 		assert.Nil(t, err)
 		authRequest := models.UserAuthParams{"admin", "badpass"}

+ 135 - 0
database/database.go

@@ -0,0 +1,135 @@
+package database
+
+import (
+	"encoding/json"
+	"errors"
+
+	"github.com/rqlite/gorqlite"
+)
+
+const NETWORKS_TABLE_NAME = "networks"
+const NODES_TABLE_NAME = "nodes"
+const DELETED_NODES_TABLE_NAME = "deletednodes"
+const USERS_TABLE_NAME = "users"
+const DNS_TABLE_NAME = "dns"
+const EXT_CLIENT_TABLE_NAME = "extclients"
+const INT_CLIENTS_TABLE_NAME = "intclients"
+const PEERS_TABLE_NAME = "peers"
+const DATABASE_FILENAME = "netmaker.db"
+
+// == ERROR CONSTS ==
+const NO_RECORD = "no result found"
+const NO_RECORDS = "could not find any records"
+
+var Database gorqlite.Connection
+
+func InitializeDatabase() error {
+
+	conn, err := gorqlite.Open("http://")
+	if err != nil {
+		return err
+	}
+
+	// sqliteDatabase, _ := sql.Open("sqlite3", "./database/"+dbFilename)
+	Database = conn
+	Database.SetConsistencyLevel("strong")
+	createTables()
+	return nil
+}
+
+func createTables() {
+	createTable(NETWORKS_TABLE_NAME)
+	createTable(NODES_TABLE_NAME)
+	createTable(DELETED_NODES_TABLE_NAME)
+	createTable(USERS_TABLE_NAME)
+	createTable(DNS_TABLE_NAME)
+	createTable(EXT_CLIENT_TABLE_NAME)
+	createTable(INT_CLIENTS_TABLE_NAME)
+	createTable(PEERS_TABLE_NAME)
+}
+
+func createTable(tableName string) error {
+	_, err := Database.WriteOne("CREATE TABLE IF NOT EXISTS " + tableName + " (key TEXT NOT NULL UNIQUE PRIMARY KEY, value TEXT)")
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func isJSONString(value string) bool {
+	var jsonInt interface{}
+	return json.Unmarshal([]byte(value), &jsonInt) == nil
+}
+
+func Insert(key string, value string, tableName string) error {
+	if key != "" && value != "" && isJSONString(value) {
+		_, err := Database.WriteOne("INSERT OR REPLACE INTO " + tableName + " (key, value) VALUES ('" + key + "', '" + value + "')")
+		if err != nil {
+			return err
+		}
+		return nil
+	} else {
+		return errors.New("invalid insert " + key + " : " + value)
+	}
+}
+
+func InsertPeer(key string, value string) error {
+	if key != "" && value != "" && isJSONString(value) {
+		_, err := Database.WriteOne("INSERT OR REPLACE INTO " + PEERS_TABLE_NAME + " (key, value) VALUES ('" + key + "', '" + value + "')")
+		if err != nil {
+			return err
+		}
+		return nil
+	} else {
+		return errors.New("invalid peer insert " + key + " : " + value)
+	}
+}
+
+func DeleteRecord(tableName string, key string) error {
+	_, err := Database.WriteOne("DELETE FROM " + tableName + " WHERE key = \"" + key + "\"")
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func DeleteAllRecords(tableName string) error {
+	_, err := Database.WriteOne("DELETE TABLE " + tableName)
+	if err != nil {
+		return err
+	}
+	err = createTable(tableName)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func FetchRecord(tableName string, key string) (string, error) {
+	results, err := FetchRecords(tableName)
+	if err != nil {
+		return "", err
+	}
+	if results[key] == "" {
+		return "", errors.New(NO_RECORD)
+	}
+	return results[key], nil
+}
+
+func FetchRecords(tableName string) (map[string]string, error) {
+	row, err := Database.QueryOne("SELECT * FROM " + tableName + " ORDER BY key")
+	if err != nil {
+		return nil, err
+	}
+	records := make(map[string]string)
+	for row.Next() { // Iterate and fetch the records from result cursor
+		var key string
+		var value string
+		row.Scan(&key, &value)
+		records[key] = value
+	}
+	if len(records) == 0 {
+		return nil, errors.New(NO_RECORDS)
+	}
+	return records, nil
+}

+ 54 - 0
database/statics.go

@@ -0,0 +1,54 @@
+package database
+
+import (
+	"encoding/json"
+	"strings"
+)
+
+func SetPeers(newPeers map[string]string, networkName string) bool {
+	areEqual := PeersAreEqual(newPeers, networkName)
+	if !areEqual {
+		jsonData, err := json.Marshal(newPeers)
+		if err != nil {
+			return false
+		}
+		InsertPeer(networkName, string(jsonData))
+		return true
+	}
+	return !areEqual
+}
+func GetPeers(networkName string) (map[string]string, error) {
+	record, err := FetchRecord(PEERS_TABLE_NAME, networkName)
+	if err != nil && !IsEmptyRecord(err) {
+		return nil, err
+	}
+	currentDataMap := make(map[string]string)
+	if IsEmptyRecord(err) {
+		return currentDataMap, nil
+	}
+	err = json.Unmarshal([]byte(record), &currentDataMap)
+	return currentDataMap, err
+}
+
+func PeersAreEqual(toCompare map[string]string, networkName string) bool {
+	currentDataMap, err := GetPeers(networkName)
+	if err != nil {
+		return false
+	}
+	if len(currentDataMap) != len(toCompare) {
+		return false
+	}
+	for k := range currentDataMap {
+		if toCompare[k] != currentDataMap[k] {
+			return false
+		}
+	}
+	return true
+}
+
+func IsEmptyRecord(err error) bool {
+	if err == nil {
+		return false
+	}
+	return strings.Contains(err.Error(), NO_RECORD) || strings.Contains(err.Error(), NO_RECORDS)
+}

BIN
docs/_build/doctrees/architecture.doctree


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


BIN
docs/_build/doctrees/environment.pickle


BIN
docs/_build/doctrees/external-clients.doctree


BIN
docs/_build/doctrees/getting-started.doctree


BIN
docs/_build/doctrees/index.doctree


BIN
docs/_build/doctrees/quick-start.doctree


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


BIN
docs/_build/doctrees/support.doctree


BIN
docs/_build/doctrees/troubleshoot.doctree


BIN
docs/_build/doctrees/usage.doctree


+ 1 - 1
docs/_build/html/.buildinfo

@@ -1,4 +1,4 @@
 # Sphinx build info version 1
 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: b4f54218c96970315e0631746ba1b7fb
+config: ea2669ddaa1c21d925350f2fad6e510c
 tags: 645f666f9bcd5a90fca523b33c5a78b7

BIN
docs/_build/html/_images/create-net.png


BIN
docs/_build/html/_images/exclient1.png


BIN
docs/_build/html/_images/exclient2.png


BIN
docs/_build/html/_images/exclient3.png


BIN
docs/_build/html/_images/exclient4.png


BIN
docs/_build/html/_images/netmaker-node.png


+ 39 - 27
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.
 
-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, MongoDB, 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.
 
 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. 
 
@@ -63,8 +63,7 @@ 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.
 
-Netmaker's netclient, the agent which controls networking on all nodes, relies heavily on systemd as of version 0.3. This reliance is being reduced but is currently a core dependency, causing most of the limitations and incompatibilities. 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.
-
+Netmaker's netclient, the agent which controls networking on all nodes, can be run as a CLI or as a system daemon. 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.
 
 Components
 ===========
@@ -82,29 +81,31 @@ Most server settings are configurable via a config file, or by environment varia
 
 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.
 
-The Netmaker server interacts with (as of v0.3) a MongoDB instance, which 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 rqlite, a distributed version of sqlite, which 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.
 
 
 Netclient
 ----------------
 
-The netclient is, at its core, a golang binary. Source code can be found in the netclient folder of the Netmaker `GitHub Repository <https://github.com/gravitl/netmaker/tree/master/netclient>`_. The binary, by itself, can be compiled for most systems. However, this binary is designed to manage a certain number of Operating Systems. As of version 0.3, it requires systemd in order to manage the host system appropriately. It may be installable, and it may even make the machine a part of the mesh network, but it will not function in entirely (see Compatible Systems for more info) without systemd.
+The netclient is, at its core, a golang binary. Source code can be found in the netclient folder of the Netmaker `GitHub Repository <https://github.com/gravitl/netmaker/tree/master/netclient>`_. The binary, by itself, can be compiled for most systems. However, this binary is designed to manage a certain number of Operating Systems. As of version 0.5, the netclient can be run as a system daemon on linux distributions with systemd, or as an "unmanaged" client on distributions without systemd.
+
+The netclient is installed via a simple bash script, which pulls the latest binary and runs 'register' and 'join' commands.
 
-The netclient is installed via a simple bash script, which pulls the latest binary and runs install command.
+The 'register' command adds a WireGuard tunnel directly to the netmaker server, for all subsequent communication.
 
-The install command registers the machine with the Netmaker server using sensible defaults, which can be overridden with a config file or environment variables. Assuming the netclient has a valid key (or the network allows manual node signup), it will be registered in the Netmaker network, which will return configuration details about how to set up the local network. 
+The 'join' command attempts to add the machine to the Netmaker network using sensible defaults, which can be overridden with a config file or environment variables. Assuming the netclient has a valid key (or the network allows manual node signup), it will be registered into the Netmaker network, and will be returned necessary configuration details for how to set up its local network. 
 
-The netclient then sets itself up in systemd, and configures WireGuard. At this point it should be part of the network.
+The netclient then sets up the systemd daemon (if running in daemon mode), and configures WireGuard. At this point it should be part of the network.
 
-On a periodic basis (systemd timer), the netclient performs a "check in." It will authenticate with the server, and check to see if anything has changed in the network. It will also post changes about its own local configuration if there. If there has been a change, the server will return new configurations and the netclient will reconfigure the network.
+If running in daemon mode, on a periodic basis (systemd timer), the netclient performs a "check in." It will authenticate with the server, and check to see if anything has changed in the network. It will also post changes about its own local configuration if there. If there has been a change, the server will return new configurations and the netclient will reconfigure the network. If not running in daemon mode, it is up to the operator to perform check ins (netclient checkin -n < network name >).
 
 The check in process is what allows Netmaker to create dynamic mesh networks. As nodes are added to, removed from, and modified on the network, other nodes are notified, and make appropriate changes.
 
 
-MongoDB
+rqlite
 --------
 
-As of v0.3, Netmaker uses MongoDB as its database, and interacts with a MongoDB instance to store and retrieve information about nodes, networks, and users. Netmaker is rapidly evolving, and MongoDB provides a flexible database structure that accelerates development. However, MongoDB is also the heaviest component of Netmaker (high cpu/memory consumption), and is set to be replaced by a lighter-weight, SQL-based database in the future.
+As of v0.7, Netmaker uses rqlite, a distributed (RAFT consensus) database, and interacts with this database to store and retrieve information about nodes, networks, and users. With the 0.7 refactor, additional database support is very easy to implement. Netmaker uses simple key value lookups to run the networks, and the database was designed to be extensible, so support for key-value stores and other SQL-based databases can be achieved by changing a single file.
 
 Netmaker UI
 ---------------
@@ -117,10 +118,20 @@ Netmaker can be used in its entirety without the UI, but the UI makes things a l
 CoreDNS
 --------
 
-v0.3 introduced the concept of private DNS management for 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.
 
 Worth considering is that CoreDNS requires port 53 on the Netmaker host system, which may cause conflicts depending on your operating system. This is explained in the :doc:`Server Installation <./server-installation>` guide.
 
+External Client
+----------------
+
+The external client is simply a manually configured WireGuard connection to your network, which Netmaker helps to manage.
+
+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. 
+
+Netmaker v0.5 introduces the "external client" to handle any devices which are not currently compatible with the netclient, including Windows, iPhone, Android, and Mac. Over time, this list will be eliminated and there may not even be a need for the external client.
+
+External clients hook into a Netmaker network via an "Ingress Gateway," which is configured for a given node and allows traffic to flow into the network.
 
 Technical Process
 ====================
@@ -132,22 +143,25 @@ Below is a high level, step-by-step overview of the flow of communications withi
 3. Both of the above requests are routed to the server via an API call from the front end
 4. Admin runs the netclient install script on any given node (machine).
 5. Netclient decodes key, which contains the GRPC server location and port
-6. Netclient retrieves/sets local information, including open ports for WireGuard, public IP, and generating key pairs for peers
-7. Netclient reaches out to GRPC server with this information, authenticating via access key.
-8. Netmaker server verifies information and creates the node, setting default values for any missing information. 
-9. Timestamp is set for the network (see #16). 
-10. Netmaker returns settings as response to netclient. Some settings may be added or modified based on the network.
-11. Netclient recieves response. If successful, it takes any additional info returned from Netmaker and configures the local system/WireGuard
-12. Netclient sends another request to Netmaker's GRPC server, this time to retrieve the peers list (all other clients in the network).
-13. Netmaker sends back peers list, including current known configurations of all nodes in network.
-14. Netclient configures WireGuard with this information. At this point, the node is fully configured as a part of the network and should be able to reach the other nodes via private address.
-15. Netclient begins daemon (system timer) to run check in's with the server. It awaits changes, reporting local changes, and retrieving changes from any other nodes in the network.
-16. Other netclients on the network, upon checking in with the Netmaker server, will see that the timestamp has updated, and they will retrieve a new peers list, completing the update cycle.
+6. Netclient uses information to register and set up WireGuard tunnel to GRPC server
+7. Netclient retrieves/sets local information, including open ports for WireGuard, public IP, and generating key pairs for peers
+8. Netclient reaches out to GRPC server with this information, authenticating via access key.
+9. Netmaker server verifies information and creates the node, setting default values for any missing information. 
+10. Timestamp is set for the network (see #16). 
+11. Netmaker returns settings as response to netclient. Some settings may be added or modified based on the network.
+12. Netclient recieves response. If successful, it takes any additional info returned from Netmaker and configures the local system/WireGuard
+13. Netclient sends another request to Netmaker's GRPC server, this time to retrieve the peers list (all other clients in the network).
+14. Netmaker sends back peers list, including current known configurations of all nodes in network.
+15. Netclient configures WireGuard with this information. At this point, the node is fully configured as a part of the network and should be able to reach the other nodes via private address.
+16. Netclient begins daemon (system timer) to run check in's with the server. It awaits changes, reporting local changes, and retrieving changes from any other nodes in the network.
+17. Other netclients on the network, upon checking in with the Netmaker server, will see that the timestamp has updated, and they will retrieve a new peers list, completing the update cycle.
 
 
 Compatible Systems for Netclient
 ==================================
 
+To manage a node manually, the Netclient can be compiled and run for most linux distibutions, with a prerequisite of WireGuard.
+
 To manage a node automatically, the Netmaker client (netclient) requires **systemd-based linux.** Compatible systems include:
         - Fedora
         - Ubuntu
@@ -169,8 +183,6 @@ To manage DNS (optional), the node must have systemd-resolved. Systems that have
 Limitations
 ===========
 
-Install limitations mostly include platform-specific limitations, such as needing systemd or systemd-resolved (see above). In addition the Netmaker platform has some additional limitations:
+Install limitations mostly include platform-specific limitations, such as needing systemd or systemd-resolved (see above). 
 
-- **Double NAT**: Netmaker is currently unable to route traffic for devices behind a "double NAT".
-- **CGNAT**: Netmaker is currently unable to route traffic for for devices behind a "carrier-grade NAT".
-- **Windows/iPhone/Android**: To reiterate the systemd limitation, Netmaker is not currently configured to support "end user" devices such as Windows desktops and phones generally. In v0.4, Netmaker will introduce external device gateways to allow this traffic (and many other sorts of devices).
+In addition the Netmaker is currently unable to route traffic for for devices behind a "carrier-grade NAT". This will be solved in a future release with the introduction of relay servers.

+ 27 - 2
docs/_build/html/_sources/client-installation.rst.txt

@@ -112,15 +112,40 @@ Managing Netclient
 Viewing Logs
 ---------------
 
+**to view current networks**
+  ``netclient list``
+
+**to tail logs**
+  ``journalctl -u netclient@<net name> -f``
+
+**to view all logs**
+  ``journalctl -u netclient@<net name>``
+
+**to get most recent log run**
+  ``systemctl status netclient@<net name>``
+
 Making Updates
 ----------------
 
+``vim /etc/netclient/netconfig-<network>``
+
+Change any of the variables in this file, and changes will be pushed to the server and processed locally on the next checkin.
+
+For instance, change the private address, endpoint, or name. See above example config file for details
+
+
 Adding/Removing Networks
 ---------------------------
 
+``netclient join -t <token>``
+
+Set any of the above flags (netclient join --help) to override settings for joining the network. 
+If a key is provided (-k), then a token is unnecessary, but grpc, server, ports, and network must all be provided via flags.
+
+
 Uninstalling
 ---------------
 
-Troubleshooting
------------------
+``netclient uninstall``
+
 

+ 40 - 0
docs/_build/html/_sources/external-clients.rst.txt

@@ -17,3 +17,43 @@ By using this method, you can hook any machine into a netmaker network that can
 It is recommended to run the netclient where compatible, but for all other cases, a machine can be configured as an external client.
 
 Important to note, an external client is not **reachable** by the network, meaning the client can establish connections to other machines, but those machines cannot independently establish a connection back. The External Client method should only be used in use cases where one wishes to access resource runnin on the virtual network, and **not** for use cases where one wishes to make a resource accessible on the network. For that, use netclient.
+
+Configuring an Ingress Gateway
+==================================
+
+External Clients must attach to an Ingress Gateway. By default, your network will not have an ingress gateway. To configure an ingress gateway, you can use any node in your network, but it should have a public IP address (not behind a NAT). Your Netmaker server can be an ingress gateway and makes for a good default choice if you are unsure of which node to select.
+
+.. image:: images/exclient1.png
+   :width: 80%
+   :alt: Gateway
+   :align: center
+
+Adding Clients to a Gateway
+=============================
+
+Once you have configured a node as a gateway, you can then add clients to that gateway. Clients will be able to access other nodes in the network just as the gateway node does.
+
+.. image:: images/exclient2.png
+   :width: 80%
+   :alt: Gateway
+   :align: center
+
+After creating a client, you can edit the name to something more logical.
+
+.. image:: images/exclient3.png
+   :width: 80%
+   :alt: Gateway
+   :align: center
+
+Then, you can either download the configuration file directly, or scan the QR code from your phone (assuming you have the WireGuard app installed). It will accept the configuration just as it would accept a typical WireGuard configuration file.
+
+.. image:: images/exclient4.png
+   :width: 80%
+   :alt: Gateway
+   :align: center
+
+Example config file: 
+
+.. literalinclude:: ./examplecode/myclient.conf
+
+Your client should now be able to access the network! A client can be invalidated at any time by simply deleting it from the UI.

+ 112 - 134
docs/_build/html/_sources/getting-started.rst.txt

@@ -1,148 +1,126 @@
-===============
+=================
 Getting Started
+=================
+
+Once you have Netmaker installed via the :doc:`Quick Install <./quick-start>` guide, you can use this Getting Started guide to help create and manage your first network.
+
+Setup
+=================
+
+#. Create your admin user, with a username and password.
+#. Login with your new user
+#. Create your first network by clicking on Create Network
+
+.. image:: images/create-net.png
+   :width: 80%
+   :alt: Create Network Screen
+   :align: center
+
+This network should have a sensible name (nodes will use it to set their interfaces).
+
+More importantly, it should have a non-overlapping, private address range. 
+
+If you are running a small (less than 254 machines) network, and are unsure of which CIDR's to use, you could consider:
+
+- 10.11.12.0/24
+- 10.20.30.0/24
+- 100.99.98.0/24
+
+Once your network is created, you should see that the netmaker server has added itself to the network. From here, you can move on to adding additional nodes to the network.
+
+.. image:: images/netmaker-node.png
+   :width: 80%
+   :alt: Node Screen
+   :align: center
+
+
+Create Key
+------------
+
+Adding nodes to the network typically requires a key.
+
+#. Click on the ACCESS KEYS tab and select the network you created.
+#. Click ADD NEW ACCESS KEY
+#. Give it a name (ex: "mykey") and a number of uses (ex: 25)
+#. Click CREATE KEY (**Important:** Do not click out of the following screen until you have saved your key details. It will appear only once.)
+#. Copy the bottom command under "Your agent install command with access token" and save it somewhere locally. E.x: ``curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netclient-install.sh | KEY=vm3ow4thatogiwnsla3thsl3894ths sh -``.
+
+.. image:: images/access-key.png
+   :width: 80%
+   :alt: Access Key Screen
+   :align: center
+
+You will use this command to install the netclient on your nodes. There are three different values for three different scenarios: 
+
+* The **Access Key** value is the secret string that will allow your node to authenticate with the Netmaker network. This can be used with existing netclient installations where additional configurations (such as setting the server IP manually) may be required. This is not typical. E.g. ``netclient join -k <access key> -s grpc.myserver.com -p 50051``
+* The **Access Token** value is a base64 encoded string that contains the server IP and grpc port, as well as the access key. This is decoded by the netclient and can be used with existing netclient installations like this: ``netclient join -t <access token>``. You should use this method for adding a network to a node that is already on a network. For instance, Node A is in the **mynet** network and now you are adding it to **default**.
+* The **install command** value is a curl command that can be run on Linux systems. It is a simple script that downloads the netclient binary and runs the install command all in one.
+  
+Networks can also be enabled to allow nodes to sign up without keys at all. In this scenario, nodes enter a "pending state" and are not permitted to join the network until an admin approves them.
+
+Deploy Nodes
+=================
+
+0. Prereqisite: Every machine on which you install should have wireguard and systemd already installed.
+
+1. SSH to each machine 
+2. ``sudo su -``
+3. **Prerequisite Check:** Every Linux machine on which you run the netclient must have WireGuard and systemd installed
+4. Run the install command, Ex: ``curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netclient-install.sh | KEY=vm3ow4thatogiwnsla3thsl3894ths sh -``
+
+You should get output similar to the below. The netclient retrieves local settings, submits them to the server for processing, and retrieves updated settings. Then it sets the local network configuration. For more information about this process, see the :doc:`client installation <./client-installation>` documentation. If this process failed and you do not see your node in the console (see below), then reference the :doc:`troubleshooting <./troubleshoot>` documentation.
+
+.. image:: images/nc-install-output.png
+   :width: 80%
+   :alt: Output from Netclient Install
+   :align: center
+
+
+.. image:: images/nm-node-success.png
+   :width: 80%
+   :alt: Node Success
+   :align: center
+
+
+Repeat the above steps for every machine you would like to add to your network. You can re-use the same install command so long as you do not run out of uses on your access key (after which it will be invalidated and deleted).
+
+Once installed on all nodes, you can test the connection by pinging the private address of any node from any other node.
+
+
+.. image:: images/ping-node.png
+   :width: 80%
+   :alt: Node Success
+   :align: center
+
+Manage Nodes
 ===============
 
-Netmaker is a tool for creating and managing virtual overlay networks. If you have servers spread across multiple locations, data centers, or clouds, this platform can make life easier. Netmaker takes all those machines and puts them on a single, secure, flat network so that they can all talk to each other easily and securely. It's like a VPC but of arbitrary computers.
-
-Netmaker can be compared to and covers use cases similar to Tailscale, ZeroTier, or Nebula, but Netmaker does more than that, while being faster, more dynamic and more flexible.
-
-Netmaker uses kernel WireGuard to create encrypted tunnels between every node in your virtual network. Netmaker's `netclient` agent is self-updating and pulls any necessary changes (such as new peers) from the main server. 
-
-Use Cases
-=========
- 1. Create a flat, secure network between multiple/hybrid cloud environments
- 2. Integrate central and edge services
- 3. Secure a home or office network while providing remote connectivity
- 4. Manage cryptocurrency proof-of-stake machines
- 6. Provide an additional layer of security on an existing network
- 7. Encrypt Kubernetes inter-node communications
- 8. Secure site-to-site connections
-
-
-Compatible Systems
-==================
-
-To manage a server automatically, Netmaker requires **systemd-based linux.** Compatible systems include:
-        - Fedora
-        - Ubuntu
-        - Debian
-        - Mint
-        - SUSE
-        - RHEL
-        - Raspian.
-        - Arch
-        - CentOS
-        - CoreOS
-      
-To manage DNS (optional), the server must have systemd-resolved. Systems that have this enabled include:
-        - Arch
-        - Debian
-        - Ubuntu
-        - SUSE
-
-
-In future releases, we will support other platforms such as Windows, MacOS, iOS, Android, and more. 
-
-Video Tutorials and Articles:
-
-
-
-Quick Start
-===========
-
-[Intro/Overview Video Tutorial](https://youtu.be/PWLPT320Ybo)  
-[Site-to-Site Video Tutorial](https://youtu.be/krCKBJhwwDk)  
-
-### Note about permissions
-The default installation requires special privileges on the server side, because Netmaker will control the local kernel Wireguard. This can be turned off and run in non-privileged mode if necessary (but disables some features). For more details, see the **Usage** docs.
-
-### Prereqs
- 1. A running linux server to host Netmaker, with an IP reachable by your computers (Debian-based preferred but not required).
- 2. Linux installed on the above server (Debian-based preferred but not required).
- 3. Install Docker and Docker Compose if running in Docker Mode (see below).
- 4. System dependencies installed:
-	 - Docker (if running in default Docker mode. DO NOT use snap install for docker.)
-	 - Docker Compose
-	 - Wireguard + Resolvectl (if running in default Client mode)
-
-#### CoreDNS Preparation
-v0.3 introduces CoreDNS as a private nameserver. To run CoreDNS on your server host, you must disable systemd-resolved to open port 53: 
-1. systemctl stop systemd-resolved
-2. systemctl disable systemd-resolved
-3. vim /etc/systemd/resolved.conf
-	 - uncomment **DNS=** and add 8.8.8.8 or whatever is your preference
-	 - uncomment **DNSStubListener=** and set to **"no"**
- 4. sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
-
-
-
-### Launch Netmaker
-Note, this installs Netmaker with CoreDNS and a Netclient (privileged).  If you want to run the server non-privileged or without CoreDNS, see the advanced usage docs. 
-
-1. Clone this repo or just copy contents of "docker-compose.yml" to your Netmaker server (from prereqs).
-2. In docker-compose.yml, change BACKEND_URL to the public IP of your server.
-3. Run `sudo docker-compose up -d`
-4. Navigate to your server's IP in the browser and you should see the Netmaker UI asking to create a new admin user.
-5. Create a new admin user
-6. You are now ready to begin using Netmaker. 
-
-### Create a Network
-You can also just use the "default" network.
-1. Click "CREATE NETWORK" in the upper left of your console
-2. Enter a valid address range, e.g. 10.11.12.0/24
-3. Enter a name such as "homenet"
-4. Additional options:
-	- **Dual Stack**: Machines will recieve a private IPv6 address in addition to their IPv4 address.
-	- **Local:** Will use local address range for endpoints instead of public. Use Case: Home or Office network where most devices do not have public IP's. In this case you can create a gateway into the network after creating the Local Network.
-
-After Network creation, you can edit the network in the NETWORK DETAILS pane, modifying the address range and default options. You can also toggle on **Allow Node Signup Without Keys**, which makes the next step unnecessary, but allows anyone to create a node in your network, which will be cordoned in pending state.
-
-### Create Keys
-1. Click the "ACCESS KEYS" tab
-2. Click "ADD NEW ACCESSS KEY"
-3. Give your key a name and number of uses
-4. Several values will be displayed. Save these somewhere, as they will only be displayed once:
-	- **Access Key:** Use only in special edge cases where server connection string must be modified
-	- **Access Token:** Use on machines that already have the netclient utility
-	- **Install Command:** Use on machines that do not have the netclient utility
-
-### Install Agent:
-For machines **without** netclient, run the install command (from above): `curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.3/netclient-install.sh | KEY=<your access key> sh -`  
-For machines **with** netclient run the following (with access token from above): `sudo netclient -c install -t <access token>`
-For networks with **manual signup** enabled (see above), install using the network name: `sudo netclient -c install -n <network name>`
-
-### Manage Nodes
 Your machines should now be visible in the control pane. 
-**Modify nodes:** Click the pencil icon in the NODES pane to modify details like WireGuard port, address, and node name. You can also **DELETE** nodes here and they will lose network access.
-**Approve nodes:** If a node is in pending state (signed up without key), you can approve it. An icon will appear for pending nodes that need approval.
 
-**Gateway Mode:** Click the Gateway icon to enable gateway mode on a given node. A popup will allow you to choose an existing network, or enter a custom address range.
-*Example: You create a network in netmaker called Homenet. It has several machines on your home server. You create another network called Cloudnet. It has several machines in AWS. You have one server (server X) which is added to both networks. On Cloudnet, you make Server X a gateway to Homenet. Now, the cloudnet machines have access to your homenet machines. via  Server X.*
+.. image:: images/nodes.png
+   :width: 80%
+   :alt: Node Success
+   :align: center
+
+You can view/modify/delete any node by selecting it in the NODES tab. For instance, you can change the name to something more sensible like "workstation" or "api server". You can also modify network settings here, such as keys or the WireGuard port. These settings will be picked up by the node on its next check in. For more information, see Advanced Configuration in the :doc:`Using Netmaker <./usage>` docs.
 
-*On Homenet, you add Server Y, a machine in AWS, and make it a gateway to a custom address range 172.16.0.0/16. The machines on your home network now have access to any AWS machines in that address range via Server Y*
+.. image:: images/node-details.png
+   :width: 80%
+   :alt: Node Success
+   :align: center
 
-### Manage DNS
-On the DNS tab you can create custom DNS entries for a given network.
 
- 1. All dns entries will be *postfixed* with a private TLD of the network name, for example, ".mynet"
- 2. Default DNS is created for node name + TLD, for instance, node-c42wt.mynet. This is not editable.
- 3. Click ADD ENTRY to add custom DNS
-	 - You can click CHOOSE NODE to direct DNS to a specific node in the network
-	 - You can also specify any custom address you would like, which can be outside the network (for instance, the IP for google.com)
-	 - Add a dns entry name, which will be postfixed with the network TLD. E.g. if you enter "privateapi.com", it will become "privateapi.com.networkname" 
 
-### Uninstalling Client
-To uninstall the client from a network: `sudo netclient -c remove -n < networkname >`
-To uninstall entirely, run the above for each network,  and then run `sudo rm -rf /etc/netclient`
+Nodes can be added/removed/modified on the network at any time. Nodes can also be added to multiple Netmaker networks. Any changes will get picked up by any nodes on a given network, and will take aboue ~30 seconds to take effect.
 
-### Uninstralling Netmaker
-To uninstall the netmaker server, simply run `docker-compose down`
+Uninstalling the netclient
+=============================
 
-#### LICENSE
+1. To remove your nodes from the default network, run the following on each node: ``sudo netclient leave -n default``
+2. To remove the netclient entirely from each node, run ``sudo rm -rf /etc/netclient`` (after running the first step)
 
-Netmaker's source code and all artifacts in this repository are freely available. All versions are published under the Server Side Public License (SSPL), version 1, which can be found here: [LICENSE.txt](./LICENSE.txt).
+Uninstalling Netmaker
+===========================
 
-#### CONTACT
+To uninstall Netmaker from the server, simply run ``docker-compose down`` or ``docker-compose down --volumes`` to remove the docker volumes for a future installation.
 
-Email: [email protected]  
-Discord: https://discord.gg/zRb9Vfhk8A

+ 5 - 0
docs/_build/html/_sources/index.rst.txt

@@ -58,6 +58,11 @@ A quick start guide to getting up and running with Netmaker and WireGuard as qui
 
    quick-start
 
+.. toctree::
+   :maxdepth: 2
+
+   getting-started
+
 Server Installation
 --------------------
 

+ 131 - 93
docs/_build/html/_sources/quick-start.rst.txt

@@ -1,137 +1,175 @@
-===========
-Quick Start
-===========
+===============
+Quick Install
+===============
+
+This quick start guide is an **opinionated** guide for getting up and running with Netmaker as quickly as possible.
+
+0. Introduction
+==================
+
+We assume for this installation that you want all of the Netmaker features enabled, want your server to be secure, and want it to be accessible from anywhere. 
+
+This instance will not be HA. However, it should comfortably handle around one hundred concurrent clients and support most use cases.
 
-Introduction
-==============
+If you are deploying for an enterprise use case, please contact [email protected] for support.
 
-This is a guide to getting up and running with Netmaker as quickly as possible. 
+By the end of this guide, you will have Netmaker installed on a public VM linked to your custom domain, secured behind an Nginx reverse proxy.
 
-By default, Netmaker ships with DNS Mode, Client Mode, and Secure GRPC enabled. However, these features require special permissions and are not necessary for a simple setup, so we are going to deploy without them. To learn more about enabling these features, check out the :doc:`installation docs <./server-installation>`.
+If this configuration does not fit your use case, see the :doc:`Advanced Installation <./server-installation>` docs. 
 
-Prerequisites
+
+
+1. Prerequisites
 ==================
- #. A Linux server to host Netmaker, with an external IP reachable by your nodes (will be referred to as **your-host** in  document).
- #. Docker and Docker Compose installed on the above server. Follow the official `Docker instructions <https://docs.docker.com/engine/install/>`_ for installing Docker and Docker Compose on your system.
- #. All network nodes should be systemd-based (see Compatibility under :doc:`Architecture <./architecture>` docs)
+-  **Virtual Machine**
+   
+   - Preferably from a cloud provider (e.x: DigitalOcean, Linode, AWS, GCP, etc.)
+   - Public, static IP 
+   - Min 2GB RAM, 1 CPU (4GB RAM, 2CPU preferred)
+   - 5GB+ of storage
+   - Ubuntu  20.04 Installed
 
-Install
-==============
-#. ``ssh root@your-host``
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.slim.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+- **Domain**
 
-Navigate to the IP address of your host in the browser. You should see the below screen. If not, please see the Quick Start section of the :doc:`troubleshooting <./support>` docs.
+  - A publicly owned domain (e.x. example.com, mysite.biz) 
+  - Permission and access to modify DNS records via DNS service (e.x: Route53)
 
-.. image:: images/create-user.png
-   :width: 80%
-   :alt: Create User Screen
-   :align: center
+2. Install Dependencies
+========================
 
-Setup
-=================
+``ssh root@your-host``
 
-#. Create your admin user, with a username and password.
-#. Login with your new user
-#. Examine the **default** network. Click on DEFAULT under NETWORK DETAILS
+Install Docker
+---------------
+Begin by installing the community version of Docker and docker-compose (there are issues with the snap version). You can follow the official `Docker instructions here <https://docs.docker.com/engine/install/>`_. Or, you can use the below series of commands which should work on Ubuntu 20.04.
 
-.. image:: images/default-net.png
-   :width: 80%
-   :alt: Create User Screen
-   :align: center
+.. code-block::
 
-This displays information about the **default** network, which is created on server startup. You can delete this network if you do not need it, but for standard use cases this network should be enough to get started. Nodes will get an address from the network address range (ADDRESSRANGE). If the range conflicts with a pre-existing private network on your devices, you may want to change this, or make a new network instead. Nodes will also get default settings from here for unset configurations. For instance, the DEFAULTKEEPALIVE field will set the PersistenKeepAlive for nodes.
+  sudo apt-get remove docker docker-engine docker.io containerd runc
+  sudo apt-get update
+  sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release
+  curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg  
+  echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
+  sudo apt-get update
+  sudo apt-get install docker-ce docker-ce-cli containerd.io
+  sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
+  sudo chmod +x /usr/local/bin/docker-compose
+  docker --version
+  docker-compose --version
 
-To get started quickly, we can just use the existing default network.
+At this point Docker should be installed.
 
-Create Key
-------------
+Install Dependencies
+-----------------------------
 
-#. Click on the ACCESS KEYS tab and select the DEFAULT network.
-#. Click ADD NEW ACCESS KEY
-#. Give it a name (ex: "mykey") and a number of uses (ex: 25)
-#. Click CREATE KEY (**Important:** Do not click out of the following screen until you have saved your key details. It will appear only once.)
-#. Copy the bottom command under "Your agent install command with access token" and save it somewhere locally. E.x: ``curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.3/scripts/netclient-install.sh | KEY=vm3ow4thatogiwnsla3thsl3894ths sh -``
+In addition to Docker, this installation requires WireGuard, Nginx, and Certbot.
 
-.. image:: images/access-key.png
-   :width: 80%
-   :alt: Access Key Screen
-   :align: center
+``sudo apt install wireguard wireguard-tools nginx certbot python3-certbot-nginx net-tools``
 
-You will use this command to install the netclient on your nodes. There are three different values for three different scenarios: 
+ 
+3. Prepare VM
+===============================
 
-* The **Access Key** value is the secret string that will allow your node to authenticate with the Netmaker network. This can be used with existing netclient installations where additional configurations (such as setting the server IP manually) may be required. This is not typical. E.g. ``netclient -c install -k <access key> -s 1.2.3.4 -p 50052``
-* The **Access Token** value is a base64 encoded string that contains the server IP and grpc port, as well as the access key. This is decoded by the netclient and can be used with existing netclient installations like this: ``netclient -c install -t <access token>``. You should use this method for adding a network to a node that is already on a network. For instance, Node A is in the **mynet** network and now you are adding it to **default**.
-* The **install command** value is a curl command that can be run on Linux systems. It is a simple script that downloads the netclient binary and runs the install command all in one.
-  
-Networks can also be enabled to allow nodes to sign up without keys at all. In this scenario, nodes enter a "pending state" and are not permitted to join the network until an admin approves them.
+Prepare Domain
+----------------------------
+1. Choose a base domain or subdomain for Netmaker. If you own **example.com**, this should be something like **netmaker.example.com**
 
-Deploy Nodes
-=================
+- You must point your wildcard domain to the public IP of your VM, e.x: *.example.com --> <your public ip>
 
-1. SSH to each machine 
-2. ``sudo su -``
-3. **Prerequisite Check:** Every Linux machine on which you run the netclient must have WireGuard and systemd installed
+2. Add an A record pointing to your VM using your DNS service provider for *.netmaker.example.com (inserting your own subdomain of course).
+3. Netmaker will create three subdomains on top of this. For the example above those subdomains would be:
 
-  * ``which wg`` (should show wg binary present)
-  * ``pidof systemd && echo "systemd found" || echo "systemd not found"``
+- dashboard.netmaker.example.com
 
-4. Run the install command, Ex: ``curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.5/scripts/netclient-install.sh | KEY=vm3ow4thatogiwnsla3thsl3894ths sh -``
+- api.netmaker.example.com
 
-You should get output similar to the below. The netclient retrieves local settings, submits them to the server for processing, and retrieves updated settings. Then it sets the local network configuration. For more information about this process, see the :doc:`client installation <./client-installation>` documentation. If this process failed and you do not see your node in the console (see below), then reference the :doc:`troubleshooting <./troubleshoot>` documentation.
+- grpc.netmaker.example.com
 
-.. image:: images/nc-install-output.png
-   :width: 80%
-   :alt: Output from Netclient Install
-   :align: center
+Moving forward we will refer to your base domain using **<your base domain>**. Replace these references with your domain (e.g. netmaker.example.com).
 
+4. ``nslookup host.<your base domain>`` (inserting your domain) should now return the IP of your VM.
 
-.. image:: images/nm-node-success.png
-   :width: 80%
-   :alt: Node Success
-   :align: center
+5. Generate SSL Certificates using certbot:
 
+``sudo certbot certonly --manual --preferred-challenges=dns --email [email protected] --server https://acme-v02.api.letsencrypt.org/directory --agree-tos --manual-public-ip-logging-ok -d "*.<your base domain>"``
 
-Repeat the above steps for every machine you would like to add to your network. You can re-use the same install command so long as you do not run out of uses on your access key (after which it will be invalidated and deleted).
+The above command (using your domain instead of <your base domain>), will prompt you to enter a TXT record in your DNS service provider. Do this, and **wait one  minute** before clicking enter, or it may fail and you will have to run the command again.
 
-Once installed on all nodes, you can test the connection by pinging the private address of any node from any other node.
+Prepare Firewall
+-----------------
 
+Make sure firewall settings are appropriate for Netmaker. You need ports 53 and 443. On the server you can run:
 
-.. image:: images/ping-node.png
-   :width: 80%
-   :alt: Node Success
-   :align: center
 
-Manage Nodes
-===============
+.. code-block::
+
+  sudo ufw allow proto tcp from any to any port 443 && sudo ufw allow dns
+
+**Based on your cloud provider, you may also need to set inbound security rules for your server. This will be dependent on your cloud provider. Be sure to check before moving on:**
+  - allow 443/tcp from all
+  - allow 53/udp from all
+
+Prepare for DNS
+----------------------------------------------------------------
+
+On Ubuntu 20.04, by default there is a service consuming port 53 related to DNS resolution. We need port 53 open in order to run our own DNS server. The below steps will disable systemd-resolved, and insert a generic DNS nameserver for local resolution.
+
+.. code-block::
+
+  systemctl stop systemd-resolved
+  systemctl disable systemd-resolved 
+  vim /etc/systemd/resolved.conf
+    *  uncomment DNS and add 8.8.8.8 or whatever reachable nameserver is your preference  *
+    *  uncomment DNSStubListener and set to "no"  *
+  ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
+
+
+Prepare Nginx
+-----------------
+
+Nginx will serve the SSL certificate with your chosen domain and forward traffic to netmaker.
+
+Get the nginx configuration file:
+
+``wget https://raw.githubusercontent.com/gravitl/netmaker/develop/nginx/netmaker-nginx-template.conf``
+
+Insert your domain in the configuration file and add to nginx:
+
+.. code-block::
+
+  sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' netmaker-nginx-template.conf
+  sudo cp netmaker-nginx-template.conf /etc/nginx/conf.d/<your base domain>.conf
+  nginx -t && nginx -s reload
+  systemctl restart nginx
+
+4. Install Netmaker
+====================
 
-Your machines should now be visible in the control pane. 
+Prepare Templates
+------------------
 
-.. image:: images/nodes.png
-   :width: 80%
-   :alt: Node Success
-   :align: center
+.. code-block::
 
-You can view/modify/delete any node by selecting it in the NODES tab. For instance, you can change the name to something more sensible like "workstation" or "api server". You can also modify network settings here, such as keys or the WireGuard port. These settings will be picked up by the node on its next check in. For more information, see Advanced Configuration in the :doc:`Using Netmaker <./usage>` docs.
+  wget https://raw.githubusercontent.com/gravitl/netmaker/develop/compose/docker-compose.quickstart.yml
+  sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' docker-compose.quickstart.yml
+  sed -i 's/SERVER_PUBLIC_IP/<your server ip>/g' docker-compose.quickstart.yml
 
-.. image:: images/node-details.png
-   :width: 80%
-   :alt: Node Success
-   :align: center
+Generate a unique master key and insert it:
 
+.. code-block::
 
+  tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo ''
+  sed -i 's/REPLACE_MASTER_KEY/<your generated key>/g' docker-compose.quickstart.yml
 
-Nodes can be added/removed/modified on the network at any time. Nodes can also be added to multiple Netmaker networks. Any changes will get picked up by any nodes on a given network, and will take aboue ~30 seconds to take effect.
+Start Netmaker
+----------------
 
-Uninstalling the netclient
-=============================
+``sudo docker-compose -f docker-compose.quickstart.yml up -d``
 
-1. To remove your nodes from the default network, run the following on each node: ``sudo netclient leave -n default``
-2. To remove the netclient entirely from each node, run ``sudo rm -rf /etc/netclient`` (after running the first step)
+navigate to dashboard.<your base domain> to see your nginx instance.
 
-Uninstralling Netmaker
-===========================
+To troubleshoot issues, start with:
 
-To uninstall Netmaker from the server, simply run ``docker-compose down`` or ``docker-compose down --volumes`` to remove the docker volumes for a future installation.
+``docker logs netmaker``
 
+Or check out the :doc:`troubleshoooting docs <./troubleshoot>`.

+ 200 - 239
docs/_build/html/_sources/server-installation.rst.txt

@@ -1,176 +1,175 @@
-====================
-Server Installation
+=================================
+Advanced Server Installation
+=================================
+
+This section outlines installing the Netmaker server, including Netmaker, Netmaker UI, rqlite, and CoreDNS
+
+System Compatibility
 ====================
 
-This section outlines installing the Netmaker server, including Netmaker, Netmaker UI, MongoDB, and CoreDNS
+Netmaker will require elevated privileges to perform network operations. Netmaker has similar limitations to :doc:`netclient <./client-installation>` (client networking agent). 
 
-Notes on Optional Features
-============================
+Typically, Netmaker is run inside of containers (Docker). To run a non-docker installation, you must run the Netmaker binary, CoreDNS binary, rqlite, and a web server directly on the host. Each of these components have their own individual requirements.
 
-There are a few key options to keep in mind when deploying Netmaker. All of the following options are enabled by default but can be disabled with a single flag at runtime (see Customization). In addition to these options, there are many more Customizable components which will be discussed later on and help to solve for special challenges and use cases.
+The quick install guide is recommended for first-time installs. 
 
-**Client Mode:** Client Mode enables Netmaker to control the underlying host server's Network. This can make management a bit easier, because Netmaker can be added into networks via a button click in the UI. This is especially useful for things like Gateways, and will open up additional options in future versions, for instance, allowing Netmaker to easily become a relay server.
+The following documents are meant for special cases like Kubernetes and LXC, or for more advanced setups. 
 
-Client Mode requires many additional privileges on the host machine, since Netmaker needs to control kernel WireGuard. Because of this, if running in Client Mode, you must run with root privileges and mount many system directories to the Netmaker container. Running without Client Mode allows you to install without privilege escalation and increases the number of compatible systems substantially.
 
-**DNS Mode:** DNS Mode enables Netmaker to write configuration files for CoreDNS, which can be set as a DNS Server for nodes. DNS Mode, paired with a CoreDNS deployment, requires use of port 53. On many linux systems (such as Ubuntu), port 53 is already in use to support local DNS, via systemd-resolved. Running in DNS Mode may require making modifications on the host machine.
+Server Configuration Reference
+==========================================
 
-**Secure GRPC**: Secure GRPC ensures all communications between nodes and the server are encrypted. Netmaker sets up a default "comms" network that exists only for nodes to connect to the server. It acts as a hub-and-spoke WireGuard network. In the below installation instructions, when port 50555 needs to be open, this is referring to the WireGuard port for Netmaker's GRPC comms. When it is port 50051, secure comms is not enabled. 
+Netmaker sets its configuration in the following order of precendence:
 
-When Secure GRPC is enabled, before any nodes can join a Netmaker network, they request to join the comms network, and are given the appropriate WireGuard configs to connect to the server. Then they are able to make requests against the private netmaker endpoint specified for the comms network (10.101.0.1 by default). If switched off, communications are not secure between the hub and nodes over GRPC (it is like http vs https), and likewise, certificates must be added to gain secure communications.
+1. Defaults
+2. Config File
+3. Environment Variables
 
-**Agent Backend:** The Agent Backend is the GRPC server (by default running on port 50051). This port is not needed for the admin server. If your use case requires special access configuration, you can run two Netmaker instances, one for the admin server, and one for node access.
+Variable Description
+----------------------
+VERBOSITY:
+    **Default:** 0
 
-**REST Backend:** Similar to the above, the REST backend runs by default on port 8081, and is used for admin API and UI access. By enabling the REST backend while disabling the Agent backend, you can separate the two functions for more restricted environments.
+    **Description:** Specify level of logging you would like on the server. Goes up to 3 for debugging.
 
 
-System Compatibility
-====================
+GRPC_SSL:
+    **Default:** "off"
 
-Both **Client Mode** and **Secure GRPC** require WireGuard to be installed on the host system, and will require elevated privileges to perform network operations..
+    **Description:** Specifies if GRPC is going over secure GRPC or SSL. This is a setting for the clients and is passed through the access token. Can be set to "on" and "off". Set to on if SSL is configured for GRPC.
 
-When both of these features are **disabled**, Netmaker can be run on any system that supports Docker, including Windows, Mac, and Linux, and other systems. With these features disabled, no special privileges are required. Netmaker will only need ports for GRPC (50051 by default), the API (8081 by default), and CoreDNS (53, if enabled).
+SERVER_API_CONN_STRING
+    **Default:** ""
 
-With Client Mode and/or Secure GRPC **enabled** (the default), Netmaker has the same limitations as the :doc:`netclient <./client-installation>` (client networking agent), because client mode just means that the Netmaker server is also running a netclient. 
+    **Description:**  Allows specification of the string used to connect to the server api. Format: IP:PORT or DOMAIN:PORT. Defaults to SERVER_HOST if not specified.
 
-These modes require privileged (root) access to the host machine. In addition, Client Mode requires multiple host directory mounts. WireGuard must be installed, the system must be systemd Linux (see :doc:`compatible systems <./architecture>` for more details).
+SERVER_GRPC_CONN_STRING
+    **Default:** ""
 
-To run a non-docker installation, you must run the Netmaker binary, CoreDNS binary, MongoDB, and a web server directly on the host. This requires all the requirements for those individual components. Our guided install assumes systemd-based linux, but there are many other ways to install Netmaker's individual components onto machines that do not support Docker. 
+    **Description:**  Allows specification of the string used to connect to grpc. Format: IP:PORT or DOMAIN:PORT. Defaults to SERVER_HOST if not specified.
 
-DNS Mode Prereqisite Setup
-====================================
+SERVER_HOST: *(depreciated, use SERVER_API_CONN_STRING and SERVER_GRPC_CONN_STRING)* 
+    **Default:** Server will perform an IP check and set automatically unless explicitly set, or DISABLE_REMOTE_IP_CHECK is set to true, in which case it defaults to 127.0.0.1
 
-If you plan on running the server in DNS Mode, know that a `CoreDNS Server <https://coredns.io/manual/toc/>`_ 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.
+    **Description:** Sets the SERVER_HTTP_HOST and SERVER_GRPC_HOST variables if they are unset. The address where traffic comes in. 
 
-However, on your host system (for Netmaker), this may conflict with an existing process. On linux systems running systemd-resolved, there is likely a service consuming port 53. The below steps will disable systemd-resolved, and replace it with a generic (e.g. Google) nameserver. Be warned that this may have consequences for any existing private DNS configuration. The following was tested on Ubuntu 20.04 and should be run prior to deploying the docker containers.
+SERVER_HTTP_HOST: *(depreciated, use SERVER_API_CONN_STRING and SERVER_GRPC_CONN_STRING)*
+    **Default:** Equals SERVER_HOST if set, "127.0.0.1" if SERVER_HOST is unset.
+    
+    **Description:** Set to make the HTTP and GRPC functions available via different interfaces/networks.
 
-1. ``systemctl stop systemd-resolved`` 
-2. ``systemctl disable systemd-resolved`` 
-3. ``vim /etc/systemd/resolved.conf``
-    * uncomment DNS and add 8.8.8.8 or whatever reachable nameserver is your preference
-    * uncomment DNSStubListener and set to "no"
-4. ``ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf``
+SERVER_GRPC_HOST: *(depreciated, use SERVER_API_CONN_STRING and SERVER_GRPC_CONN_STRING)*
+    **Default:** Equals SERVER_HOST if set, "127.0.0.1" if SERVER_HOST is unset.
 
-Port 53 should now be available for CoreDNS to use.
+    **Description:** Set to make the HTTP and GRPC functions available via different interfaces/networks.
 
-Docker Compose Install
-=======================
+API_PORT:
+    **Default:** 8081 
 
-The most simple (and recommended) way of installing Netmaker is to use one of the provided `Docker Compose files <https://github.com/gravitl/netmaker/tree/feature_v0.3.5_docs/compose>`_. Below are instructions for several different options to install Netmaker via Docker Compose, followed by an annotated reference Docker Compose in case your use case requires additional customization.
+    **Description:** The HTTP API port for Netmaker. Used for API calls / communication from front end.
 
-Slim Install - No DNS, No Client Mode, No Secure GRPC
---------------------------------------------------------
+GRPC_PORT:  
+    **Default:** 50051
 
-This is the same docker compose covered in the :doc:`quick start <./quick-start>`. It requires no special privileges and can run on any system with Docker and Docker Compose. However, it also does not have the full feature set, and lacks Client Mode and DNS Mode.
+    **Description:** The GRPC port for Netmaker. Used for communications from nodes.
 
-**Prerequisites:**
-  * ports 80, 8081, and 50051 are not blocked by firewall
-  * ports 80, 8081, 50051, and 27017 are not in use 
+MASTER_KEY:  
+    **Default:** "secretkey" 
 
-**Notes:** 
-  * You can still run the netclient on the host system even if Client Mode is not enabled. It will just be managed like the netclient on any other nodes, and will not be automatically managed by thhe server/UI.
-  * You can change the port mappings in the Docker Compose if the listed ports are already in use.
+    **Description:** The admin master key for accessing the API. Change this in any production installation.
 
-Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
+CORS_ALLOWED_ORIGIN:  
+    **Default:** "*"
 
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.slim.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+    **Description:** The "allowed origin" for API requests. Change to restrict where API requests can come from.
 
-Full Install - DNS, Client Mode, and Secure GRPC Enabled
-----------------------------------------------------------
+REST_BACKEND:  
+    **Default:** "on" 
 
-This installation gives you the fully-featured product with Client Mode and DNS Mode. 
+    **Description:** Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
 
-**Prerequisites:**
-  * systemd linux (Debian or Ubuntu reccommended)
-  * sudo privileges
-  * DNS Mode Prerequisite Setup (see above)
-  * WireGuard installed
-  * ports 80, 8081, 53, and 50555 are not blocked by firewall
-  * ports 80, 8081, 53, 50555, and 27017 are not in use
+AGENT_BACKEND:  
+    **Default:** "on" 
 
-**Notes:** 
-  * You can change the port mappings in the Docker Compose if the listed ports are already in use.
-  * You can run CoreDNS on a non-53 port, but this likely will cause issues on the client side (DNS on non-standard port). We do not recommend this and do not cover how to manage running CoreDNS on a different port for clients, which will likely have problems resolving a nameserver on a non-53 port.
+    **Description:** Enables the AGENT backend (GRPC running on GRPC_PORT at SERVER_GRPC_HOST). Change to "off" to turn off.
 
-Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
+DNS_MODE:  
+    **Default:** "off"
 
-#. ``sudo su -``
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+    **Description:** Enables DNS Mode, meaning config files will be generated for CoreDNS.
 
+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.
 
-Server Only Install - UI, DNS, Client Disabled
-------------------------------------------------
+.. literalinclude:: ../config/environments/dev.yaml
+  :language: YAML
 
-A "Server Only" install can be helpful for scenarios in which you do not want to run the UI. the UI is not mandatory for running a Netmaker network, but it makes the process easier. This mode also diables DNS and Client Modes, though you can add those back in if needed. There is no UI dependency on Client Mode or DNS Mode.
+Compose File - Annotated
+--------------------------------------
 
-**Prerequisites:**
-  * ports 8081 and 50051 are not blocked by firewall
-  * ports 8081, 50051, and 27017 are not in use
+All environment variables and options are enabled in this file. It is the equivalent to running the "full install" from the above section. However, all environment variables are included, and are set to the default values provided by Netmaker (if the environment variable was left unset, it would not change the installation). Comments are added to each option to show how you might use it to modify your installation.
 
-**Notes:**
-  * You can still run the netclient on the host system even if Client Mode is not enabled. It will just be managed like the netclient on any other nodes, and will not be automatically managed by thhe server/UI.
-  * You can change the port mappings in the Docker Compose if the listed ports are already in use.
+.. literalinclude:: ../compose/docker-compose.reference.yml
+  :language: YAML
 
-Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
 
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.server-only.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
+DNS Mode Setup
+====================================
 
-No DNS - CoreDNS Disabled, Client Enabled
-----------------------------------------------
+If you plan on running the server in DNS Mode, know that a `CoreDNS Server <https://coredns.io/manual/toc/>`_ 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.
 
-DNS Mode is currently limited to clients that can run resolvectl (systemd-resolved, see :doc:`Architecture docs <./architecture>` for more info). You may wish to disable DNS mode for various reasons. This installation option gives you the full feature set minus CoreDNS.
+However, on your host system (for Netmaker), this may conflict with an existing process. On linux systems running systemd-resolved, there is likely a service consuming port 53. The below steps will disable systemd-resolved, and replace it with a generic (e.g. Google) nameserver. Be warned that this may have consequences for any existing private DNS configuration. The following was tested on Ubuntu 20.04 and should be run prior to deploying the docker containers.
 
-**Prerequisites:**
-  * systemd linux (Debian or Ubuntu reccommended)
-  * sudo privileges
-  * WireGuard installed
-  * ports 80, 8081, and 50555 are not blocked by firewall
-  * ports 80, 8081, 50555, and 27017 are not in use
+.. code-block::
 
-**Notes:** 
-  * You can change the port mappings in the Docker Compose if the listed ports are already in use.
-  * If you would like to run DNS Mode, but disable it on some clients, this is also an option. See the :doc:`client installation <./client-installation>` documentation for more details.
+  systemctl stop systemd-resolved
+  systemctl disable systemd-resolved 
+  vim /etc/systemd/resolved.conf
+    *  uncomment DNS and add 8.8.8.8 or whatever reachable nameserver is your preference  *
+    *  uncomment DNSStubListener and set to "no"  *
+  ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
 
-Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
+Port 53 should now be available for CoreDNS to use.
 
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.nodns.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
 
-No DNS - CoreDNS Disabled, Client Enabled
+Docker Compose Install
+=======================
+
+The most simple (and recommended) way of installing Netmaker is to use one of the provided `Docker Compose files <https://github.com/gravitl/netmaker/tree/master/compose>`_. Below are instructions for several different options to install Netmaker via Docker Compose, followed by an annotated reference Docker Compose in case your use case requires additional customization.
 
-No Client - DNS Enabled, Client Disabled
----------------------------------------------
+Test Install - No DNS, No Secure GRPC
+--------------------------------------------------------
+
+This install will run Netmaker on a server without HTTPS using an IP address. This is not secure and not recommended, but can be helpful for testing.
 
-You may want to provide DNS, but do not want to run the server with special privileges, in which case you can run with just Client Mode disabled. It requires no special privileges and can run on any system with Docker and Docker Compose. 
+It also does not run the CoreDNS server, to simplify the deployment
 
 **Prerequisites:**
-  * ports 80, 8081, 53, and 50051 are not blocked by firewall
-  * ports 80, 8081, 53, 50051, and 27017 are not in use
-  * DNS Mode Prerequisite Setup (see above)
+  * server ports 80, 8081, and 50051 are not blocked by firewall
 
 **Notes:** 
-  * You can still run the netclient on the host system even if Client Mode is not enabled. It will just be managed like the netclient on any other nodes, and will not be automatically managed by thhe server/UI.
   * You can change the port mappings in the Docker Compose if the listed ports are already in use.
 
 Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
 
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.noclient.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+.. code-block::
 
+  wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.test.yml
+  sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml
+  docker-compose up -d`
 
-Reference Compose File - Annotated
---------------------------------------
 
-All environment variables and options are enabled in this file. It is the equivalent to running the "full install" from the above section. However, all environment variables are included, and are set to the default values provided by Netmaker (if the environment variable was left unset, it would not change the installation). Comments are added to each option to show how you might use it to modify your installation.
+No DNS - CoreDNS Disabled
+----------------------------------------------
 
-.. literalinclude:: ../compose/docker-compose.reference.yml
-  :language: YAML
+DNS Mode is currently limited to clients that can run resolvectl (systemd-resolved, see :doc:`Architecture docs <./architecture>` for more info). You may wish to disable DNS mode for various reasons. This installation option gives you the full feature set minus CoreDNS.
+
+To run without DNS, follow the :doc:`Quick Install <./quick-start>` guide, omitting the steps for DNS setup. In addition, when the guide has you pull (wget) the Netmaker docker-compose template, use the following link instead:
+
+#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.nodns.yml``
+
+This template is equivalent but omits CoreDNS.
 
 
 Linux Install without Docker
@@ -178,35 +177,44 @@ Linux Install without Docker
 
 Most systems support Docker, but some, such as LXC, 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). 
 
-Below is a guided set of instructions for installing without Docker on Ubuntu 20.04. Depending on your system, the steps may vary.
+To start, we recommend following the Nginx instructions in the :doc:`Quick Install <./quick-start>` guide to enable SSL for your environment.
+
+Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.
 
-MongoDB Setup
+rqlite Setup
 ----------------
-1. Install MongoDB on your server:
-    * For Ubuntu: `sudo apt install -y mongodb`
-    * For more advanced installation or other operating systems, see  the `MongoDB documentation <https://docs.mongodb.com/manual/administration/install-community/>`_.
+1. Install rqlite on your server: https://github.com/rqlite/rqlite
 
-2. Create a user:
-    * ``mongo admin``  
-    * > `db.createUser({ user: "mongoadmin" , pwd: "mongopass", roles: ["userAdminAnyDatabase", "dbAdminAnyDatabase", "readWriteAnyDatabase"]})`
+2. Run rqlite: rqlited -node-id 1 ~/node.1
 
 Server Setup
 -------------
-1. **Run the install script:** ``sudo curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.3.5/scripts/netmaker-server.sh | sh -``
+1. **Run the install script:** 
+
+``sudo curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netmaker-server.sh | sh -``
+
 2. Check status:  ``sudo journalctl -u netmaker``
 3. If any settings are incorrect such as host or mongo credentials, change them under /etc/netmaker/config/environments/< your env >.yaml and then run ``sudo systemctl restart netmaker``
 
 UI Setup
 -----------
 
-The following uses NGinx as an http server. You may alternatively use Apache or any other web server that serves static web files.
+The following uses Nginx as an http server. You may alternatively use Apache or any other web server that serves static web files.
 
-1. **Download UI asset files:** ``sudo wget -O /usr/share/nginx/html/netmaker-ui.zip https://github.com/gravitl/netmaker-ui/releases/download/latest/netmaker-ui.zip``
-2. **Unzip:** ``sudo unzip /usr/share/nginx/html/netmaker-ui.zip -d /usr/share/nginx/html``
-3. **Copy Config to Nginx:** ``sudo cp /usr/share/nginx/html/nginx.conf /etc/nginx/conf.d/default.conf``
-4. **Modify Default Config Path:** ``sudo sed -i 's/root \/var\/www\/html/root \/usr\/share\/nginx\/html/g' /etc/nginx/sites-available/default``
-5. **Change Backend URL:** ``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'``
-6. **Start Nginx:** ``sudo systemctl start nginx``
+1. Download and Unzip UI asset files
+2. Copy Config to Nginx
+3. Modify Default Config Path
+4. Change Backend URL
+5. Start Nginx
+
+.. code-block::
+  
+  sudo wget -O /usr/share/nginx/html/netmaker-ui.zip https://github.com/gravitl/netmaker-ui/releases/download/latest/netmaker-ui.zip
+  sudo unzip /usr/share/nginx/html/netmaker-ui.zip -d /usr/share/nginx/html
+  sudo cp /usr/share/nginx/html/nginx.conf /etc/nginx/conf.d/default.conf
+  sudo sed -i 's/root \/var\/www\/html/root \/usr\/share\/nginx\/html/g' /etc/nginx/sites-available/default
+  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
 
 CoreDNS Setup
 ----------------
@@ -214,150 +222,103 @@ CoreDNS Setup
 Kubernetes Install
 =======================
 
-**This configuration is coming soon.** It will allow you to deploy Netmaker on a Kubernetes cluster.
-
-Configuration Reference
-=========================
+Server Install
+--------------------------
 
-The "Reference Compose File" (above) explains many of these options. However, it is important to understand fundamentally how Netmaker sets its configuration:
+This template assumes your cluster uses Nginx for ingress with valid wildcard certificates. If using an ingress controller other than Nginx (ex: Traefik), you will need to manually modify the Ingress entries in this template to match your environment.
 
-1. Defaults
-2. Config File
-3. Environment Variables
+This template also requires RWX storage. Please change references to storageClassName in this template to your cluster's Storage Class.
 
-Variable Description
-----------------------
+``wget https://raw.githubusercontent.com/gravitl/netmaker/develop/kube/netmaker-template.yaml``
 
-SERVER_HOST: 
-    **Default:** Server will perform an IP check and set automatically unless explicitly set, or DISABLE_REMOTE_IP_CHECK is set to true, in which case it defaults to 127.0.0.1
+Replace the NETMAKER_BASE_DOMAIN references to the base domain you would like for your Netmaker services (ui,api,grpc). Typically this will be something like **netmaker.yourwildcard.com**.
 
-    **Description:** Sets the SERVER_HTTP_HOST and SERVER_GRPC_HOST variables if they are unset. The address where traffic comes in. 
+``sed -i ‘s/NETMAKER_BASE_DOMAIN/<your base domain>/g’ netmaker-template.yaml``
 
-SERVER_HTTP_HOST: 
-    **Default:** Equals SERVER_HOST if set, "127.0.0.1" if SERVER_HOST is unset.
-    
-    **Description:** Set to make the HTTP and GRPC functions available via different interfaces/networks.
+Now, assuming Ingress and Storage match correctly with your cluster configuration, you can install Netmaker.
 
-SERVER_GRPC_HOST: 
-    **Default:** Equals SERVER_HOST if set, "127.0.0.1" if SERVER_HOST is unset.
+.. code-block::
 
-    **Description:** Set to make the HTTP and GRPC functions available via different interfaces/networks.
+  kubectl create ns nm
+  kubectl config set-context --current --namespace=nm
+  kubectl apply -f netmaker-template.yaml -n nm
 
-API_PORT:  
-    **Default:** 8081 
+In about 3 minutes, everything should be up and running:
 
-    **Description:** The HTTP API port for Netmaker. Used for API calls / communication from front end.
+``kubectl get ingress nm-ui-ingress-nginx``
 
-GRPC_PORT:  
-    **Default:** 50051
+Netclient Daemonset
+--------------------------
 
-    **Description:** The GRPC port for Netmaker. Used for communications from nodes.
+The following instructions assume you have Netmaker running and a network you would like to add your cluster into. The Netmaker server does not need to be running inside of a cluster for this.
 
-MASTER_KEY:  
-    **Default:** "secretkey" 
+.. code-block::
 
-    **Description:** The admin master key for accessing the API. Change this in any production installation.
+  wget https://raw.githubusercontent.com/gravitl/netmaker/develop/kube/netclient-template.yaml
+  sed -i ‘s/ACCESS_TOKEN_VALUE/< your access token value>/g’ netclient-template.yaml
+  kubectl apply -f netclient-template.yaml
 
-CORS_ALLOWED_ORIGIN:  
-    **Default:** "*"
+For a more detailed guide on integrating Netmaker with MicroK8s, `check out this guide <https://itnext.io/how-to-deploy-a-cross-cloud-kubernetes-cluster-with-built-in-disaster-recovery-bbce27fcc9d7>`_. 
 
-    **Description:** The "allowed origin" for API requests. Change to restrict where API requests can come from.
-
-REST_BACKEND:  
-    **Default:** "on" 
-
-    **Description:** Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
-
-AGENT_BACKEND:  
-    **Default:** "on" 
-
-    **Description:** Enables the AGENT backend (GRPC running on GRPC_PORT at SERVER_GRPC_HOST). Change to "off" to turn off.
-
-CLIENT_MODE:  
-    **Default:** "on" 
-
-    **Description:** Enables Client Mode, meaning netclient will be deployed on server and will be manageable from UI. Change to "off" to turn off.
-
-DNS_MODE:  
-    **Default:** "on"
-
-    **Description:** Enables DNS Mode, meaning config files will be generated for CoreDNS.
-
-DISABLE_REMOTE_IP_CHECK:  
-    **Default:** "off" 
-
-    **Description:** If turned "on", Server will not set Host based on remote IP check. This is already overridden if SERVER_HOST is set. Turned "off" by default.
-
-MONGO_ADMIN:  
-    **Default:** "mongoadmin" 
-
-    **Description:** Admin user for MongoDB.
-
-MONGO_PASS:  
-    **Default:** "mongopass" 
-
-    **Description:** Admin password for MongoDB.
-
-MONGO_HOST:  
-    **Default:** "127.0.0.1"
-
-    **Description:** Address of MongoDB.
-
-MONGO_PORT:  
-    **Default:** "27017"
-
-    **Description:** Port of MongoDB.
-
-MONGO_OPTS:  
-    **Default:** "/?authSource=admin"
-
-    **Description:** Opts to enable admin login for Mongo.
-
-SERVER_GRPC_WIREGUARD: 
-    **Default:** "on"
-
-    **Description:** Whether to run GRPC over a WireGuard network. On by default. Secures the server comms. Switch to "off" to turn off. If off and running in production, make sure to have certificates installed to secure GRPC communications. 
+Nginx Reverse Proxy Setup with https
+====================================
 
-SERVER_GRPC_WG_INTERFACE: 
-    **Default:** "nm-grpc-wg"
+The `Swag Proxy <https://github.com/linuxserver/docker-swag>`_ makes it easy to generate a valid ssl certificate for the config bellow. Here is the `documentation <https://docs.linuxserver.io/general/swag>`_ for the installation.
 
-    **Description:** Interface to use for GRPC WireGuard network if enabled
+The following file configures Netmaker as a subdomain. This config is an adaption from the swag proxy project.
 
-SERVER_GRPC_WG_ADDRESS:
-    **Default:** "10.101.0.1"
+./netmaker.subdomain.conf:
 
-    **Description:** Private Address to use for GRPC WireGuard network if enabled
+.. code-block:: nginx
 
-SERVER_GRPC_WG_ADDRESS_RANGE:
-    **Default:** "10.101.0.0/16"
+    server {
+        listen 443 ssl;
+        listen [::]:443 ssl;
 
-    **Description:** Private Address range to use for GRPC WireGard clients if enabled. Gives 65,534 total addresses for all of netmaker. If running a larger network, will need to configure addresses differently, for instance using ipv6, or use certificates instead.
+        server_name netmaker.*; # The external URL
+        client_max_body_size 0;
 
-SERVER_GRPC_WG_PORT:
-    **Default:** 50555
+        # A valid https certificate is needed.
+        include /config/nginx/ssl.conf;
 
-    **Description:** Port to use for GRPC WireGuard if enabled
+        location / {
+            # This config file can be found at:
+            # https://github.com/linuxserver/docker-swag/blob/master/root/defaults/proxy.conf
+            include /config/nginx/proxy.conf;
 
-SERVER_GRPC_WG_PUBKEY:
-    **Default:** < generated at startup >
+            # if you use a custom resolver to find your app, needed with swag proxy
+            # resolver 127.0.0.11 valid=30s;
+            set $upstream_app netmaker-ui;                             # The internal URL
+            set $upstream_port 80;                                     # The internal Port
+            set $upstream_proto http;                                  # the protocol that is being used
+            proxy_pass $upstream_proto://$upstream_app:$upstream_port; # combine the set variables from above
+            }
+        }
 
-    **Description:** PublicKey for GRPC WireGuard interface. Generated if left blank.
+    server {
+        listen 443 ssl;
+        listen [::]:443 ssl;
 
-SERVER_GRPC_WG_PRIVKEY:
-    **Default:** < generated at startup >
+        server_name backend-netmaker.*; # The external URL
+        client_max_body_size 0;
+        underscores_in_headers on;
 
-    **Description:** PrivateKey for GRPC WireGuard interface. Generated if left blank.
+        # A valid https certificate is needed.
+        include /config/nginx/ssl.conf;
 
-SERVER_GRPC_WG_KEYREQUIRED
-    **Default:** ""
+        location / {
+            # if you use a custom resolver to find your app, needed with swag proxy
+            # resolver 127.0.0.11 valid=30s;
 
-    **Description:** Determines if an Access Key is required to join the Comms network. Blank (meaning 'no') by default. Set to "yes" to turn on.
+            set $upstream_app netmaker;                                # The internal URL
+            set $upstream_port 8081;                                   # The internal Port
+            set $upstream_proto http;                                  # the protocol that is being used
+            proxy_pass $upstream_proto://$upstream_app:$upstream_port; # combine the set variables from above
 
+            # Forces the header to be the one that is visible from the outside
+            proxy_set_header                Host backend.netmaker.example.org; # Please cange to your URL
 
-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 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
-  :language: YAML
-
+            # Pass all headers through to the backend
+            proxy_pass_request_headers      on;
+            }
+        }

+ 6 - 20
docs/_build/html/_sources/support.rst.txt

@@ -10,22 +10,15 @@ Does/Will Netmaker Support X Operating System?
 
 Netmaker is initially available on a limited number of operating systems for good reason: Every operating system is designed differently. With a small team, we can either focus on making Netmaker do a lot on a few number of operating systems, or a little on a bunch of operating systems. We chose the first option. You can view the System Compatibility docs for more info, but in general, you should only be using Netmaker on systemd linux right now.
 
-However, as of v0.4, we will technically be able to bring any operating system into the network. This is a bit of a hack. v0.4 introduces Ingress Gateways. Think of it this way. You set up a private network. You want devices to access it. You set up a single node as an "Ingress Gateway" and generate config files for "external clients." These clients are unmanaged and unmeshed, meaning they can access the network but only via the gateway. It also means they will not automatically account for changes to the network, and the user will have to update the configs manually.
+However, via "external clients", any device that supports WireGuard can be added to the network. 
 
-This lets us immediately "support" any device which can run WireGuard, which includes most operating systems at this point including phones and Windows.
-
-As we stabilize the design and feature set of Netmaker, we will expand the operating system support for Netclient which configures dynamic, fully-meshed devices. Expect to see updates about new OS support every few weeks, until eventually the Ingress Gateway becomes unnecessary (though you will still want it for certain use cases).
+In future iterations will expand the operating system support for Netclient, and devices that must use the "external client" feature can switch to Netclient.
 
 How do I install the Netclient on X?
 ---------------------------------------
 
 As per the above, there are many unsupported operating systems. You are still welcome to try, it is just an executable binary file after all. If the system is unix-based and has kernel WireGuard installed, netclient may very well mesh the device into the network. However, the service likely will encounter problems retrieving updates.
 
-Why MongoDB? SQL is better and smaller.
-----------------------------------------
-
-We are in a phase of rapid iteration. Every week the database schema changes. MongoDB makes our development process much more flexible. That said, we agree! SQL will be better for production, and indeed, we plan to switch over to SQL before v1.0, so please be patient with the resource consumption of MongoDB for the time being; it is helping to support a rapid pace of development. 
-
 
 Is Netmaker a VPN like NordNPN?
 --------------------------------
@@ -41,10 +34,11 @@ https://github.com/pivpn/pivpn
 https://github.com/subspacecloud/subspace
 https://github.com/mullvad/mullvadvpn-app
 
-Do you offer any paid support?
----------------------------------
+Do you offer any enterprise support?
+--------------------------------------
+
+If you are interested in enterprise support for your project, please contact [email protected].
 
-Not at this time, but eventually we will. If you are interested, or if you are interested in sponsoring the project generally, please contact Alex Feiszli ([email protected]).
 
 Why the SSPL License?
 ----------------------
@@ -57,14 +51,6 @@ If you have concerns about the license leading to project restrictions down the
 
 All that said, we will re-evaluate the license on a regular basis and determine if an OSI-approved license makes more sense. It's just easier to move from SSPL to another license than vice-versa.
 
-Issues, Bugs, and Feature Requests
-=====================================
-
-Issues / Bugs
-----------------
-
-Feature Requests
--------------------
 
 Contact
 ===========

+ 75 - 1
docs/_build/html/_sources/troubleshoot.rst.txt

@@ -3,17 +3,91 @@ Troubleshooting
 =================
 
 Common Issues
----------------
+--------------
+**How can I connect my Android, IOS, MacOS or Windows device to my Netmaker VPN?**
+  Currently meshing one of these devices is not supported, however it will be soon. 
+  For now you can connect to your VPN by making one of the nodes an Ingressgateway, then 
+  create an Ext Client for each device. Finally, use the official WG app or another 
+  WG configuration app to connect via QR or downloading the device's WireGuard configuration. 
+
+**I've made changes to my nodes but the nodes themselves haven't updated yet, why?**
+  Please allow your nodes to complete a check in or two, in order to reconfigure themselves.
+  In some cases, it could take up to a minute or so.
+
+**Do I have to use access keys to join a network?**
+  Although keys are the preferred way to join a network, Netmaker does allow for manual node sign-ups.
+  Simply turn on "allow manual signups" on your network and nodes will not connect until you manually aprove each one.
+
+**Is there a community or forum to ask questions about Netmaker?**
+  Yes, we have an active `discord <https://discord.gg/Pt4T9y9XK8>`_ community and issues on our `github <https://github.com/gravitl/netmaker/issues>`_ are answered frequently!
+  You can also sign-up for updates at our `gravitl site <https://gravitl.com/>`_!
 
 Server
 -------
+**Can I secure/encrypt all the traffic to my server and UI?**
+  This can fairly simple to achieve assuming you have access to a domain and are familiar with Nginx.
+  Please refer to the quick-start guide to see!
+
+**Can I connect multiple nodes (mesh clients) behind a single firewall/router?**
+  Yes! As of version 0.7 Netmaker supports UDP Hole Punching to allow this, without the use of a third party STUN server!
+  Is UDP hole punching a risk for you? Well you can turn it off and make static nodes/ports for the server to refer to as well.
+
+**What are the minimum specs to run the server?**
+  We recommend at least 1 CPU and 2 GB Memory.
+
+**Does this support IPv6 addressing?**
+  Yes, Netmaker supports IPv6 addressing. When you create a network, just make sure to turn on Dual Stack.
+  Nodes will be given IPv6 addresses along with their IPv4 address. It does not currently support IPv6 only.
+
+**Does Netmaker support Raft Consensus?**
+  Netmaker does not directly support it, but it uses `rqlite <https://github.com/rqlite/rqlite>`_ (which supports Raft) as the database.
+
+**How do I uninstall Netmaker?**
+  There is no official uninstall script for the Netmaker server at this time. If you followed the quick-start guide, simply run ``sudo docker-compose -f docker-compose.quickstart.yml down --volumes``
+  to completely wipe your server. Otherwise kill the running binary and it's up to you to remove database records/volumes.
 
 UI
 ----
+**I want to make a seperate network and give my friend access to only that network.**
+  Simply navigate to the UI (as an admin account). Select users in the top left and create them an account.
+  Select the network(s) to give them and they should be good to go! They are an admin of that network(s) only now.
+
+**I'm done with an access key, can I delete it?**
+  Simply navigate to the UI (as an admin account). Select your network of interest, then the select the ``Access Keys`` tab.
+  Then delete the rogue access key.
+
+**I can't delete my network, why?**
+  You **MUST** remove all nodes in a network before you can delete it.
+
+**Can I have multiple nodes with the same name?**
+  Yes, nodes can share names without issue. It may just be harder on you to know which is which.
 
 Agent
 -------
+**How do I connect a node to my Netmaker network with Netclient?**
+  First get your access token (not just access key), then run ``sudo netclient join -t <access token>``.
+  **NOTE:** netclient may be under /etc/netclient/, i.e run ``sudo /etc/netclient/netclient join -t <access token>``
+
+**How do I disconnect a node on a Netmaker network?**
+  In order to leave a Netmaker network, run ``sudo netclient leave -n <network-name>``
+
+**How do I check the logs of my agent on a node?**
+  You will need sudo/root permissions, but you can run ``sudo systemctl status netclient@<insert network name>``
+  or you may also run ``sudo journalctl -u netclient@<network name>``. 
+  Note for journalctl: you should hit the ``end`` key to get to view the most recent logs quickly or use ``journalctl -u netclient@<network name> -f`` instead.
+
+**Can I check the configuration of my node on the node?**
+  **A:** Yes, on the node simply run ``sudo cat /etc/netclient/netconfig-<network name>`` and you should see what your current configuration is! 
+  You can also see the current WireGuard configuration with ``sudo wg show``
+
+**I am done with the agent on my machine, can I uninstall it?**
+  Yes, on the node simply run ``sudo /etc/netclient/netclient uninstall``. 
+
 
 CoreDNS
 --------
+**Is CoreDNS required to use Netmaker?**
+  CoreDNS is not required. Simply start your server with ``DNS_MODE="off"``.
 
+**What is the minimum DNS entry value I can use?**
+  Netmaker supports down to two characters for DNS names for your networks domains**

+ 3 - 18
docs/_build/html/_sources/usage.rst.txt

@@ -19,21 +19,6 @@ Video Tutorials
 
 Written Tutorials
 -----------------
-* `Kubernetes Cross-cloud cluster <https://itnext.io/how-to-deploy-a-single-kubernetes-cluster-across-multiple-clouds-using-k3s-and-wireguard-a5ae176a6e81>`_: Tutorial on setting up cross-cloud Kubernetes clusters using Netmaker.
-
-Basic
-=====
-
-Local Network
-=============
-  
-Site-to-Site
-============
-
-Dual Stack with IPv6
-====================
-
-Kubernetes Node Network
-========================
-
-
+* `K3s Cross-cloud cluster <https://itnext.io/how-to-deploy-a-single-kubernetes-cluster-across-multiple-clouds-using-k3s-and-wireguard-a5ae176a6e81>`_: Tutorial on setting up cross-cloud K3s clusters using Netmaker.
+* `MicroK8s Cross-cloud cluster <https://itnext.io/how-to-deploy-a-cross-cloud-kubernetes-cluster-with-built-in-disaster-recovery-bbce27fcc9d7>`_: Tutorial on setting up cross-cloud MicroK8s clusters using Netmaker.
+* `Secure access to private services <https://afeiszli.medium.com/how-to-enable-secure-access-to-your-hosted-services-using-netmaker-and-wireguard-1b3282d4b7aa>`_: Tutorial on setting up secure Nextcloud with Netmaker.

+ 1 - 1
docs/_build/html/_static/documentation_options.js

@@ -1,6 +1,6 @@
 var DOCUMENTATION_OPTIONS = {
     URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
-    VERSION: '0.5',
+    VERSION: '0.7',
     LANGUAGE: 'None',
     COLLAPSE_INDEX: false,
     BUILDER: 'html',

+ 54 - 19
docs/_build/html/about.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>About &#8212; Netmaker 0.5 documentation</title>
+    <title>About &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -299,81 +299,95 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
-    </li></ul>
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
-      <ul class="md-nav__list"> 
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
       <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
@@ -412,6 +426,13 @@
       <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
+      
+    
     </li></ul>
     
     </li>
@@ -475,6 +496,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>

+ 54 - 19
docs/_build/html/api.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>API Reference &#8212; Netmaker 0.5 documentation</title>
+    <title>API Reference &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -279,81 +279,95 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
-    </li></ul>
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
-      <ul class="md-nav__list"> 
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
       <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
@@ -392,6 +406,13 @@
       <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
+      
+    
     </li></ul>
     
     </li>
@@ -455,6 +476,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>

+ 86 - 41
docs/_build/html/architecture.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Architecture &#8212; Netmaker 0.5 documentation</title>
+    <title>Architecture &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -56,7 +56,7 @@
     <link rel="author" title="About these documents" href="about.html" />
     <link rel="index" title="Index" href="genindex.html" />
     <link rel="search" title="Search" href="search.html" />
-    <link rel="next" title="Quick Start" href="quick-start.html" />
+    <link rel="next" title="Quick Install" href="quick-start.html" />
     <link rel="prev" title="About" href="about.html" />
   
    
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -268,11 +268,13 @@
         </li>
         <li class="md-nav__item"><a href="#netclient" class="md-nav__link">Netclient</a>
         </li>
-        <li class="md-nav__item"><a href="#mongodb" class="md-nav__link">MongoDB</a>
+        <li class="md-nav__item"><a href="#rqlite" class="md-nav__link">rqlite</a>
         </li>
         <li class="md-nav__item"><a href="#netmaker-ui" class="md-nav__link">Netmaker UI</a>
         </li>
         <li class="md-nav__item"><a href="#coredns" class="md-nav__link">CoreDNS</a>
+        </li>
+        <li class="md-nav__item"><a href="#external-client" class="md-nav__link">External Client</a>
         </li></ul>
             </nav>
         </li>
@@ -327,81 +329,95 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
-    </li></ul>
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
-      <ul class="md-nav__list"> 
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
       <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
@@ -440,6 +456,13 @@
       <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
+      
+    
     </li></ul>
     
     </li>
@@ -503,6 +526,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>
@@ -780,11 +817,13 @@
         </li>
         <li class="md-nav__item"><a href="#netclient" class="md-nav__link">Netclient</a>
         </li>
-        <li class="md-nav__item"><a href="#mongodb" class="md-nav__link">MongoDB</a>
+        <li class="md-nav__item"><a href="#rqlite" class="md-nav__link">rqlite</a>
         </li>
         <li class="md-nav__item"><a href="#netmaker-ui" class="md-nav__link">Netmaker UI</a>
         </li>
         <li class="md-nav__item"><a href="#coredns" class="md-nav__link">CoreDNS</a>
+        </li>
+        <li class="md-nav__item"><a href="#external-client" class="md-nav__link">External Client</a>
         </li></ul>
             </nav>
         </li>
@@ -829,7 +868,7 @@
 
 <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>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, MongoDB, 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.</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>
 
@@ -840,7 +879,7 @@
 
 <h3 id="systemd">SystemD<a class="headerlink" href="#systemd" title="Permalink to this headline">¶</a></h3>
 <p>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.</p>
-<p>Netmaker’s netclient, the agent which controls networking on all nodes, relies heavily on systemd as of version 0.3. This reliance is being reduced but is currently a core dependency, causing most of the limitations and incompatibilities. 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.</p>
+<p>Netmaker’s netclient, the agent which controls networking on all nodes, can be run as a CLI or as a system daemon. 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.</p>
 
 
 
@@ -852,20 +891,21 @@
 <p>The Netmaker server acts as an API to the front end, and as a GRPC server to the machines in the network. GRPC is much faster and more efficient than standard API calls, which increases the speed of transactions. For this reason, the Netmaker server exposes two ports: The default for the API is 8081, and the default for GRPC is 50051. Either the API or the GRPC server can be disabled on any given Netmaker instance can be disabled, allowing you to deploy two different servers for managing the API (which is largely for the admin’s use) and GRPC (which is largely for the nodes’ use).</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>The Netmaker server interacts with (as of v0.3) a MongoDB instance, which 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 rqlite, a distributed version of sqlite, which 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>
 
 
 <h3 id="netclient">Netclient<a class="headerlink" href="#netclient" title="Permalink to this headline">¶</a></h3>
-<p>The netclient is, at its core, a golang binary. Source code can be found in the netclient folder of the Netmaker <a class="reference external" href="https://github.com/gravitl/netmaker/tree/master/netclient">GitHub Repository</a>. The binary, by itself, can be compiled for most systems. However, this binary is designed to manage a certain number of Operating Systems. As of version 0.3, it requires systemd in order to manage the host system appropriately. It may be installable, and it may even make the machine a part of the mesh network, but it will not function in entirely (see Compatible Systems for more info) without systemd.</p>
-<p>The netclient is installed via a simple bash script, which pulls the latest binary and runs install command.</p>
-<p>The install command registers the machine with the Netmaker server using sensible defaults, which can be overridden with a config file or environment variables. Assuming the netclient has a valid key (or the network allows manual node signup), it will be registered in the Netmaker network, which will return configuration details about how to set up the local network.</p>
-<p>The netclient then sets itself up in systemd, and configures WireGuard. At this point it should be part of the network.</p>
-<p>On a periodic basis (systemd timer), the netclient performs a “check in.” It will authenticate with the server, and check to see if anything has changed in the network. It will also post changes about its own local configuration if there. If there has been a change, the server will return new configurations and the netclient will reconfigure the network.</p>
+<p>The netclient is, at its core, a golang binary. Source code can be found in the netclient folder of the Netmaker <a class="reference external" href="https://github.com/gravitl/netmaker/tree/master/netclient">GitHub Repository</a>. The binary, by itself, can be compiled for most systems. However, this binary is designed to manage a certain number of Operating Systems. As of version 0.5, the netclient can be run as a system daemon on linux distributions with systemd, or as an “unmanaged” client on distributions without systemd.</p>
+<p>The netclient is installed via a simple bash script, which pulls the latest binary and runs ‘register’ and ‘join’ commands.</p>
+<p>The ‘register’ command adds a WireGuard tunnel directly to the netmaker server, for all subsequent communication.</p>
+<p>The ‘join’ command attempts to add the machine to the Netmaker network using sensible defaults, which can be overridden with a config file or environment variables. Assuming the netclient has a valid key (or the network allows manual node signup), it will be registered into the Netmaker network, and will be returned necessary configuration details for how to set up its local network.</p>
+<p>The netclient then sets up the systemd daemon (if running in daemon mode), and configures WireGuard. At this point it should be part of the network.</p>
+<p>If running in daemon mode, on a periodic basis (systemd timer), the netclient performs a “check in.” It will authenticate with the server, and check to see if anything has changed in the network. It will also post changes about its own local configuration if there. If there has been a change, the server will return new configurations and the netclient will reconfigure the network. If not running in daemon mode, it is up to the operator to perform check ins (netclient checkin -n &lt; network name &gt;).</p>
 <p>The check in process is what allows Netmaker to create dynamic mesh networks. As nodes are added to, removed from, and modified on the network, other nodes are notified, and make appropriate changes.</p>
 
 
-<h3 id="mongodb">MongoDB<a class="headerlink" href="#mongodb" title="Permalink to this headline">¶</a></h3>
-<p>As of v0.3, Netmaker uses MongoDB as its database, and interacts with a MongoDB instance to store and retrieve information about nodes, networks, and users. Netmaker is rapidly evolving, and MongoDB provides a flexible database structure that accelerates development. However, MongoDB is also the heaviest component of Netmaker (high cpu/memory consumption), and is set to be replaced by a lighter-weight, SQL-based database in the future.</p>
+<h3 id="rqlite">rqlite<a class="headerlink" href="#rqlite" title="Permalink to this headline">¶</a></h3>
+<p>As of v0.7, Netmaker uses rqlite, a distributed (RAFT consensus) database, and interacts with this database to store and retrieve information about nodes, networks, and users. With the 0.7 refactor, additional database support is very easy to implement. Netmaker uses simple key value lookups to run the networks, and the database was designed to be extensible, so support for key-value stores and other SQL-based databases can be achieved by changing a single file.</p>
 
 
 <h3 id="netmaker-ui">Netmaker UI<a class="headerlink" href="#netmaker-ui" title="Permalink to this headline">¶</a></h3>
@@ -874,10 +914,17 @@
 
 
 <h3 id="coredns">CoreDNS<a class="headerlink" href="#coredns" title="Permalink to this headline">¶</a></h3>
-<p>v0.3 introduced the concept of private DNS management for 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>
 <p>Worth considering is that CoreDNS requires port 53 on the Netmaker host system, which may cause conflicts depending on your operating system. This is explained in the <a class="reference internal" href="server-installation.html"><span class="doc">Server Installation</span></a> guide.</p>
 
 
+<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>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>Netmaker v0.5 introduces the “external client” to handle any devices which are not currently compatible with the netclient, including Windows, iPhone, Android, and Mac. Over time, this list will be eliminated and there may not even be a need for the external client.</p>
+<p>External clients hook into a Netmaker network via an “Ingress Gateway,” which is configured for a given node and allows traffic to flow into the network.</p>
+
+
 
 <h2 id="technical-process">Technical Process<a class="headerlink" href="#technical-process" title="Permalink to this headline">¶</a></h2>
 <p>Below is a high level, step-by-step overview of the flow of communications within Netmaker (assuming Netmaker has already been installed):</p>
@@ -887,6 +934,7 @@
 <li><p>Both of the above requests are routed to the server via an API call from the front end</p></li>
 <li><p>Admin runs the netclient install script on any given node (machine).</p></li>
 <li><p>Netclient decodes key, which contains the GRPC server location and port</p></li>
+<li><p>Netclient uses information to register and set up WireGuard tunnel to GRPC server</p></li>
 <li><p>Netclient retrieves/sets local information, including open ports for WireGuard, public IP, and generating key pairs for peers</p></li>
 <li><p>Netclient reaches out to GRPC server with this information, authenticating via access key.</p></li>
 <li><p>Netmaker server verifies information and creates the node, setting default values for any missing information.</p></li>
@@ -902,6 +950,7 @@
 
 
 <h2 id="compatible-systems-for-netclient">Compatible Systems for Netclient<a class="headerlink" href="#compatible-systems-for-netclient" title="Permalink to this headline">¶</a></h2>
+<p>To manage a node manually, the Netclient can be compiled and run for most linux distibutions, with a prerequisite of WireGuard.</p>
 <dl class="simple">
 <dt>To manage a node automatically, the Netmaker client (netclient) requires <strong>systemd-based linux.</strong> Compatible systems include:</dt><dd><ul class="simple">
 <li><p>Fedora</p></li>
@@ -927,12 +976,8 @@
 
 
 <h2 id="limitations">Limitations<a class="headerlink" href="#limitations" title="Permalink to this headline">¶</a></h2>
-<p>Install limitations mostly include platform-specific limitations, such as needing systemd or systemd-resolved (see above). In addition the Netmaker platform has some additional limitations:</p>
-<ul class="simple">
-<li><p><strong>Double NAT</strong>: Netmaker is currently unable to route traffic for devices behind a “double NAT”.</p></li>
-<li><p><strong>CGNAT</strong>: Netmaker is currently unable to route traffic for for devices behind a “carrier-grade NAT”.</p></li>
-<li><p><strong>Windows/iPhone/Android</strong>: To reiterate the systemd limitation, Netmaker is not currently configured to support “end user” devices such as Windows desktops and phones generally. In v0.4, Netmaker will introduce external device gateways to allow this traffic (and many other sorts of devices).</p></li>
-</ul>
+<p>Install limitations mostly include platform-specific limitations, such as needing systemd or systemd-resolved (see above).</p>
+<p>In addition the Netmaker is currently unable to route traffic for for devices behind a “carrier-grade NAT”. This will be solved in a future release with the introduction of relay servers.</p>
 
 
 
@@ -960,12 +1005,12 @@
             </a>
           
           
-            <a href="quick-start.html" title="Quick Start"
+            <a href="quick-start.html" title="Quick Install"
                class="md-flex md-footer-nav__link md-footer-nav__link--next"
                rel="next">
             <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title"><span
                 class="md-flex__ellipsis"> <span
-                class="md-footer-nav__direction"> Next </span> Quick Start </span>
+                class="md-footer-nav__direction"> Next </span> Quick Install </span>
             </div>
             <div class="md-flex__cell md-flex__cell--shrink"><i
                 class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>

+ 80 - 72
docs/_build/html/client-installation.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Client Installation &#8212; Netmaker 0.5 documentation</title>
+    <title>Client Installation &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -57,7 +57,7 @@
     <link rel="index" title="Index" href="genindex.html" />
     <link rel="search" title="Search" href="search.html" />
     <link rel="next" title="External Clients" href="external-clients.html" />
-    <link rel="prev" title="Server Installation" href="server-installation.html" />
+    <link rel="prev" title="Advanced Server Installation" href="server-installation.html" />
   
    
 
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -279,61 +279,82 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
     </li></ul>
@@ -342,26 +363,26 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      <a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      <a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
       
     
     </li>
@@ -389,7 +410,7 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
     </li></ul>
@@ -442,8 +463,6 @@
         <li class="md-nav__item"><a href="#adding-removing-networks" class="md-nav__link">Adding/Removing Networks</a>
         </li>
         <li class="md-nav__item"><a href="#uninstalling" class="md-nav__link">Uninstalling</a>
-        </li>
-        <li class="md-nav__item"><a href="#troubleshooting" class="md-nav__link">Troubleshooting</a>
         </li></ul>
             </nav>
         </li></ul>
@@ -507,53 +526,32 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
-    </li></ul>
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
-      <ul class="md-nav__list"> 
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#basic" class="md-nav__link">Basic</a>
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#local-network" class="md-nav__link">Local Network</a>
-      
-    
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#site-to-site" class="md-nav__link">Site-to-Site</a>
-      
+    </li></ul>
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#dual-stack-with-ipv6" class="md-nav__link">Dual Stack with IPv6</a>
-      
-    
-    </li>
+      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
+      <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="usage.html#kubernetes-node-network" class="md-nav__link">Kubernetes Node Network</a>
+      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
       
     
     </li></ul>
@@ -647,13 +645,6 @@
       <a href="support.html#faq" class="md-nav__link">FAQ</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="support.html#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a>
-      
-    
     </li>
     <li class="md-nav__item">
     
@@ -797,8 +788,6 @@
         <li class="md-nav__item"><a href="#adding-removing-networks" class="md-nav__link">Adding/Removing Networks</a>
         </li>
         <li class="md-nav__item"><a href="#uninstalling" class="md-nav__link">Uninstalling</a>
-        </li>
-        <li class="md-nav__item"><a href="#troubleshooting" class="md-nav__link">Troubleshooting</a>
         </li></ul>
             </nav>
         </li></ul>
@@ -882,7 +871,8 @@
 </pre></div>
 </div>
 <p><code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">netclient</span> <span class="pre">join</span> <span class="pre">--help</span></code></p>
-<div class="highlight-YAML notranslate"><div class="highlight"><pre><span></span><span class="nt">NAME</span><span class="p">:</span>
+<div class="highlight-YAML notranslate"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">alex@workstation:~$ sudo netclient join --help</span>
+<span class="l l-Scalar l-Scalar-Plain">NAME</span><span class="p p-Indicator">:</span>
    <span class="l l-Scalar l-Scalar-Plain">netclient join - Join a Netmaker network.</span>
 
 <span class="nt">USAGE</span><span class="p">:</span>
@@ -890,7 +880,7 @@
 
 <span class="nt">OPTIONS</span><span class="p">:</span>
    <span class="l l-Scalar l-Scalar-Plain">--network value, -n value            Network to perform specified action against. (default</span><span class="p p-Indicator">:</span> <span class="s">"all"</span><span class="l l-Scalar l-Scalar-Plain">) [$NETCLIENT_NETWORK]</span>
-   <span class="l l-Scalar l-Scalar-Plain">--password value, -p value           Password for authenticating with netmaker. (default</span><span class="p p-Indicator">:</span> <span class="s">"badpassword"</span><span class="l l-Scalar l-Scalar-Plain">) [$NETCLIENT_PASSWORD]</span>
+   <span class="l l-Scalar l-Scalar-Plain">--password value, -p value           Password for authenticating with netmaker. [$NETCLIENT_PASSWORD]</span>
    <span class="l l-Scalar l-Scalar-Plain">--endpoint value, -e value           Reachable (usually public) address for WireGuard (not the private WG address). [$NETCLIENT_ENDPOINT]</span>
    <span class="l l-Scalar l-Scalar-Plain">--macaddress value, -m value         Mac Address for this machine. Used as a unique identifier within Netmaker network. [$NETCLIENT_MACADDRESS]</span>
    <span class="l l-Scalar l-Scalar-Plain">--publickey value, --pubkey value    Public Key for WireGuard Interface. [$NETCLIENT_PUBLICKEY]</span>
@@ -908,9 +898,10 @@
    <span class="l l-Scalar l-Scalar-Plain">--key value, -k value                Access Key for signing up machine with Netmaker server during initial 'add'. [$NETCLIENT_ACCESSKEY]</span>
    <span class="l l-Scalar l-Scalar-Plain">--token value, -t value              Access Token for signing up machine with Netmaker server during initial 'add'. [$NETCLIENT_ACCESSTOKEN]</span>
    <span class="l l-Scalar l-Scalar-Plain">--localrange value                   Local Range if network is local, for instance 192.168.1.0/24. [$NETCLIENT_LOCALRANGE]</span>
-   <span class="l l-Scalar l-Scalar-Plain">--dns value                          Sets private dns if 'on'. Ignores if 'off'. Will retrieve from network if unset. [$NETCLIENT_DNS]</span>
+   <span class="l l-Scalar l-Scalar-Plain">--dns value                          Sets private dns if 'on'. Ignores if 'off'. Will retrieve from network if unset. (default</span><span class="p p-Indicator">:</span> <span class="s">"on"</span><span class="l l-Scalar l-Scalar-Plain">) [$NETCLIENT_DNS]</span>
    <span class="l l-Scalar l-Scalar-Plain">--islocal value                      Sets endpoint to local address if 'yes'. Ignores if 'no'. Will retrieve from network if unset. [$NETCLIENT_IS_LOCAL]</span>
    <span class="l l-Scalar l-Scalar-Plain">--isdualstack value                  Sets ipv6 address if 'yes'. Ignores if 'no'. Will retrieve from network if unset. [$NETCLIENT_IS_DUALSTACK]</span>
+   <span class="l l-Scalar l-Scalar-Plain">--udpholepunch value                 Turns on udp holepunching if 'yes'. Ignores if 'no'. Will retrieve from network if unset. [$NETCLIENT_UDP_HOLEPUNCH]</span>
    <span class="l l-Scalar l-Scalar-Plain">--ipforwarding value                 Sets ip forwarding on if 'on'. Ignores if 'off'. On by default. (default</span><span class="p p-Indicator">:</span> <span class="s">"on"</span><span class="l l-Scalar l-Scalar-Plain">) [$NETCLIENT_IPFORWARDING]</span>
    <span class="l l-Scalar l-Scalar-Plain">--postup value                       Sets PostUp command for WireGuard. [$NETCLIENT_POSTUP]</span>
    <span class="l l-Scalar l-Scalar-Plain">--postdown value                     Sets PostDown command for WireGuard. [$NETCLIENT_POSTDOWN]</span>
@@ -924,6 +915,7 @@
 <h3 id="config-file-reference">Config File Reference<a class="headerlink" href="#config-file-reference" title="Permalink to this headline">¶</a></h3>
 <p>There is a config file for each node under /etc/netconfig-&lt;network name&gt;. You can change these values and then set “postchanges” to “true”, or go to the CLI and run <code class="docutils literal notranslate"><span class="pre">netclient</span> <span class="pre">push</span> <span class="pre">-n</span> <span class="pre">&lt;network&gt;</span></code></p>
 <div class="highlight-YAML notranslate"><div class="highlight"><pre><span></span><span class="nt">server</span><span class="p">:</span>
+    <span class="nt">corednsaddr</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">147.182.251.203</span> <span class="c1"># Address of CoreDNS Server (set locally with resolvectl)</span>
     <span class="nt">grpcaddress</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">10.101.0.1:50051</span> <span class="c1"># Address of GRPC Server (used for all interaction with server after registration)</span>
     <span class="nt">apiaddress</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">1.2.3.4:8081</span> <span class="c1"># Address of API Server (used only for registration/unregistration)</span>
     <span class="nt">accesskey</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">5qKTbTgsvb45y3qyRmWft</span> <span class="c1"># Key used to sign up with server. Used only during registration</span>
@@ -936,12 +928,12 @@
     <span class="nt">localaddress</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">192.168.1.32</span> <span class="c1"># Address on local network, used as endpoint for other local nodes for faster comms</span>
     <span class="nt">wgaddress</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">10.7.11.2</span> <span class="c1"># Private WG addres on network</span>
     <span class="nt">wgaddress6</span><span class="p">:</span> <span class="s">"f8:34:41:77:5c:15"</span> <span class="c1"># Private ipv6 address if network is dual stack</span>
-    <span class="nt">roaming</span><span class="p">:</span> <span class="s">"on"</span> <span class="c1"># Whether or not to grab new endpoint value automatically</span>
-    <span class="nt">dns</span><span class="p">:</span> <span class="s">"off"</span> <span class="c1"># Whether or not to set local DNS based on Netmaker's Private DNS server</span>
+    <span class="nt">roaming</span><span class="p">:</span> <span class="s">"yes"</span> <span class="c1"># Whether or not to grab new endpoint value automatically</span>
+    <span class="nt">dnson</span><span class="p">:</span> <span class="s">"no"</span> <span class="c1"># Whether or not to set local DNS based on Netmaker's Private DNS server</span>
     <span class="nt">islocal</span><span class="p">:</span> <span class="s">"no"</span> <span class="c1"># Based on network. If yes, will use local IP as endpoint.</span>
     <span class="nt">isdualstack</span><span class="p">:</span> <span class="s">"yes"</span> <span class="c1"># Use IPv6 in addition to IPv4</span>
     <span class="nt">isingressgateway</span><span class="p">:</span> <span class="s">"no"</span> <span class="c1"># whether or not node is an ingress gateway (will set iptables forwarding rules)</span>
-    <span class="nt">allowedips</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># not currently used</span>
+    <span class="nt">allowedips</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># additional IP's to add to client</span>
     <span class="nt">localrange</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># local range if it's a local network. For instance, 192.168.1.0/24</span>
     <span class="nt">postup</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># postup command, used by ingress/egress gateways to set iptables</span>
     <span class="nt">postdown</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># postdown command, used by ingress/egress gateways to set iptables</span>
@@ -951,9 +943,11 @@
     <span class="nt">privatekey</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># private key, set only for changing and then will revert to blank in config</span>
     <span class="nt">endpoint</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">78.170.22.168</span> <span class="c1"># public endpoint for reaching node </span>
     <span class="nt">postchanges</span><span class="p">:</span> <span class="s">"false"</span> <span class="c1"># if true, will post and config file changes on next checkin and then revert to false</span>
-    <span class="nt">ipforwarding</span><span class="p">:</span> <span class="s">"on"</span> <span class="c1"># set ip forwarding; highly recommended to leave on</span>
-<span class="nt">network</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">home</span> <span class="c1"># the network (duplicate of node.network)</span>
-<span class="nt">daemon</span><span class="p">:</span> <span class="s">"on"</span> <span class="c1"># whether or not to manage systemd</span>
+    <span class="nt">ipforwarding</span><span class="p">:</span> <span class="s">"yes"</span> <span class="c1"># set ip forwarding; highly recommended to leave on</span>
+    <span class="nt">isstatic</span><span class="p">:</span> <span class="s">"no"</span> <span class="c1"># if yes, daemon will not change pubkey, endpoint, or address</span>
+    <span class="nt">udpholepunch</span><span class="p">:</span> <span class="s">"yes"</span> <span class="c1"># run UDP hole punching (will ignore port above, e.g. 51821)</span>
+    <span class="nt">network</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">home</span> <span class="c1"># the network (duplicate of node.network)</span>
+<span class="nt">daemon</span><span class="p">:</span> <span class="s">"yes"</span> <span class="c1"># whether or not to manage systemd</span>
 <span class="nt">operatingsystem</span><span class="p">:</span> <span class="s">""</span> <span class="c1"># not currently in use</span>
 </pre></div>
 </div>
@@ -972,18 +966,32 @@
 <h2 id="managing-netclient">Managing Netclient<a class="headerlink" href="#managing-netclient" title="Permalink to this headline">¶</a></h2>
 
 <h3 id="viewing-logs">Viewing Logs<a class="headerlink" href="#viewing-logs" title="Permalink to this headline">¶</a></h3>
+<dl class="simple">
+<dt><strong>to view current networks</strong></dt><dd><p><code class="docutils literal notranslate"><span class="pre">netclient</span> <span class="pre">list</span></code></p>
+</dd>
+<dt><strong>to tail logs</strong></dt><dd><p><code class="docutils literal notranslate"><span class="pre">journalctl</span> <span class="pre">-u</span> <span class="pre">netclient@&lt;net</span> <span class="pre">name&gt;</span> <span class="pre">-f</span></code></p>
+</dd>
+<dt><strong>to view all logs</strong></dt><dd><p><code class="docutils literal notranslate"><span class="pre">journalctl</span> <span class="pre">-u</span> <span class="pre">netclient@&lt;net</span> <span class="pre">name&gt;</span></code></p>
+</dd>
+<dt><strong>to get most recent log run</strong></dt><dd><p><code class="docutils literal notranslate"><span class="pre">systemctl</span> <span class="pre">status</span> <span class="pre">netclient@&lt;net</span> <span class="pre">name&gt;</span></code></p>
+</dd>
+</dl>
 
 
 <h3 id="making-updates">Making Updates<a class="headerlink" href="#making-updates" title="Permalink to this headline">¶</a></h3>
+<p><code class="docutils literal notranslate"><span class="pre">vim</span> <span class="pre">/etc/netclient/netconfig-&lt;network&gt;</span></code></p>
+<p>Change any of the variables in this file, and changes will be pushed to the server and processed locally on the next checkin.</p>
+<p>For instance, change the private address, endpoint, or name. See above example config file for details</p>
 
 
 <h3 id="adding-removing-networks">Adding/Removing Networks<a class="headerlink" href="#adding-removing-networks" title="Permalink to this headline">¶</a></h3>
+<p><code class="docutils literal notranslate"><span class="pre">netclient</span> <span class="pre">join</span> <span class="pre">-t</span> <span class="pre">&lt;token&gt;</span></code></p>
+<p>Set any of the above flags (netclient join –help) to override settings for joining the network.
+If a key is provided (-k), then a token is unnecessary, but grpc, server, ports, and network must all be provided via flags.</p>
 
 
 <h3 id="uninstalling">Uninstalling<a class="headerlink" href="#uninstalling" title="Permalink to this headline">¶</a></h3>
-
-
-<h3 id="troubleshooting">Troubleshooting<a class="headerlink" href="#troubleshooting" title="Permalink to this headline">¶</a></h3>
+<p><code class="docutils literal notranslate"><span class="pre">netclient</span> <span class="pre">uninstall</span></code></p>
 
 
 
@@ -998,7 +1006,7 @@
     <div class="md-footer-nav">
       <nav class="md-footer-nav__inner md-grid">
           
-            <a href="server-installation.html" title="Server Installation"
+            <a href="server-installation.html" title="Advanced Server Installation"
                class="md-flex md-footer-nav__link md-footer-nav__link--prev"
                rel="prev">
               <div class="md-flex__cell md-flex__cell--shrink">
@@ -1007,7 +1015,7 @@
               <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
                 <span class="md-flex__ellipsis">
                   <span
-                      class="md-footer-nav__direction"> Previous </span> Server Installation </span>
+                      class="md-footer-nav__direction"> Previous </span> Advanced Server Installation </span>
               </div>
             </a>
           

+ 54 - 19
docs/_build/html/conduct.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Code of Conduct &#8212; Netmaker 0.5 documentation</title>
+    <title>Code of Conduct &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -279,81 +279,95 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
-    </li></ul>
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
-      <ul class="md-nav__list"> 
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
       <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
@@ -392,6 +406,13 @@
       <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
+      
+    
     </li></ul>
     
     </li>
@@ -455,6 +476,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>

+ 54 - 19
docs/_build/html/contribute.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Contribute &#8212; Netmaker 0.5 documentation</title>
+    <title>Contribute &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -279,81 +279,95 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
-    </li></ul>
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
-      <ul class="md-nav__list"> 
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
       <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
@@ -392,6 +406,13 @@
       <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
+      
+    
     </li></ul>
     
     </li>
@@ -455,6 +476,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>

+ 90 - 19
docs/_build/html/external-clients.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>External Clients &#8212; Netmaker 0.5 documentation</title>
+    <title>External Clients &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -279,81 +279,95 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
-    </li></ul>
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
-      <ul class="md-nav__list"> 
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
       <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
@@ -392,6 +406,13 @@
       <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
+      
+    
     </li></ul>
     
     </li>
@@ -459,6 +480,10 @@
         <li class="md-nav__item"><a href="#external-clients--page-root" class="md-nav__link">External Clients</a><nav class="md-nav">
               <ul class="md-nav__list">
         <li class="md-nav__item"><a href="#introduction" class="md-nav__link">Introduction</a>
+        </li>
+        <li class="md-nav__item"><a href="#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+        </li>
+        <li class="md-nav__item"><a href="#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
         </li></ul>
             </nav>
         </li>
@@ -471,6 +496,20 @@
       <a href="#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>
@@ -729,6 +768,10 @@
         <li class="md-nav__item"><a href="#external-clients--page-root" class="md-nav__link">External Clients</a><nav class="md-nav">
               <ul class="md-nav__list">
         <li class="md-nav__item"><a href="#introduction" class="md-nav__link">Introduction</a>
+        </li>
+        <li class="md-nav__item"><a href="#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+        </li>
+        <li class="md-nav__item"><a href="#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
         </li></ul>
             </nav>
         </li>
@@ -759,6 +802,34 @@
 <p>Important to note, an external client is not <strong>reachable</strong> by the network, meaning the client can establish connections to other machines, but those machines cannot independently establish a connection back. The External Client method should only be used in use cases where one wishes to access resource runnin on the virtual network, and <strong>not</strong> for use cases where one wishes to make a resource accessible on the network. For that, use netclient.</p>
 
 
+<h2 id="configuring-an-ingress-gateway">Configuring an Ingress Gateway<a class="headerlink" href="#configuring-an-ingress-gateway" title="Permalink to this headline">¶</a></h2>
+<p>External Clients must attach to an Ingress Gateway. By default, your network will not have an ingress gateway. To configure an ingress gateway, you can use any node in your network, but it should have a public IP address (not behind a NAT). Your Netmaker server can be an ingress gateway and makes for a good default choice if you are unsure of which node to select.</p>
+<a class="reference internal image-reference" href="_images/exclient1.png"><img alt="Gateway" class="align-center" src="_images/exclient1.png" style="width: 80%;"/></a>
+
+
+<h2 id="adding-clients-to-a-gateway">Adding Clients to a Gateway<a class="headerlink" href="#adding-clients-to-a-gateway" title="Permalink to this headline">¶</a></h2>
+<p>Once you have configured a node as a gateway, you can then add clients to that gateway. Clients will be able to access other nodes in the network just as the gateway node does.</p>
+<a class="reference internal image-reference" href="_images/exclient2.png"><img alt="Gateway" class="align-center" src="_images/exclient2.png" style="width: 80%;"/></a>
+<p>After creating a client, you can edit the name to something more logical.</p>
+<a class="reference internal image-reference" href="_images/exclient3.png"><img alt="Gateway" class="align-center" src="_images/exclient3.png" style="width: 80%;"/></a>
+<p>Then, you can either download the configuration file directly, or scan the QR code from your phone (assuming you have the WireGuard app installed). It will accept the configuration just as it would accept a typical WireGuard configuration file.</p>
+<a class="reference internal image-reference" href="_images/exclient4.png"><img alt="Gateway" class="align-center" src="_images/exclient4.png" style="width: 80%;"/></a>
+<p>Example config file:</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">Interface</span><span class="p">]</span>
+<span class="n">Address</span> <span class="o">=</span> <span class="mf">10.7.11.5</span><span class="o">/</span><span class="mi">32</span>
+<span class="n">PrivateKey</span> <span class="o">=</span> <span class="n">EJf6Yy51M</span><span class="o">/</span><span class="n">YDaZgedRpuxMmrqul35WfjmHvRZR1rQ0U</span><span class="o">=</span>
+
+<span class="p">[</span><span class="n">Peer</span><span class="p">]</span>
+<span class="n">PublicKey</span> <span class="o">=</span> <span class="n">m</span><span class="o">/</span><span class="n">RPuMVsbpgQ</span><span class="o">+</span><span class="n">RkxlgK2mG</span><span class="o">+</span><span class="n">dDFlzqn</span><span class="o">+</span><span class="n">ua2zJt8Wn7GA</span><span class="o">=</span>
+<span class="n">AllowedIPs</span> <span class="o">=</span> <span class="mf">10.7.11.0</span><span class="o">/</span><span class="mi">24</span>
+<span class="n">Endpoint</span> <span class="o">=</span> <span class="mf">3.236.60.247</span><span class="p">:</span><span class="mi">51822</span>
+<span class="n">PersistentKeepalive</span> <span class="o">=</span> <span class="mi">20</span>
+
+</pre></div>
+</div>
+<p>Your client should now be able to access the network! A client can be invalidated at any time by simply deleting it from the UI.</p>
+
+
 
 
           </article>

+ 46 - 53
docs/_build/html/genindex.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Index &#8212; Netmaker 0.5 documentation</title>
+    <title>Index &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -79,7 +79,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -165,7 +165,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -177,13 +177,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -277,61 +277,82 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
     </li></ul>
@@ -340,26 +361,26 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      <a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      <a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
       
     
     </li>
@@ -387,7 +408,7 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
     </li></ul>
@@ -453,53 +474,32 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
-    </li></ul>
-    
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
-      <ul class="md-nav__list"> 
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
-      
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#basic" class="md-nav__link">Basic</a>
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#local-network" class="md-nav__link">Local Network</a>
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#site-to-site" class="md-nav__link">Site-to-Site</a>
-      
+    </li></ul>
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#dual-stack-with-ipv6" class="md-nav__link">Dual Stack with IPv6</a>
-      
-    
-    </li>
+      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
+      <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="usage.html#kubernetes-node-network" class="md-nav__link">Kubernetes Node Network</a>
+      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
       
     
     </li></ul>
@@ -593,13 +593,6 @@
       <a href="support.html#faq" class="md-nav__link">FAQ</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="support.html#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a>
-      
-    
     </li>
     <li class="md-nav__item">
     

+ 611 - 176
docs/_build/html/getting-started.html

@@ -46,16 +46,18 @@
   
   
   
-    <title>Getting Started &#8212; Netmaker 0.3.5 documentation</title>
+    <title>Getting Started &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
     <script src="_static/jquery.js"></script>
     <script src="_static/underscore.js"></script>
     <script src="_static/doctools.js"></script>
+    <link rel="author" title="About these documents" href="about.html" />
     <link rel="index" title="Index" href="genindex.html" />
     <link rel="search" title="Search" href="search.html" />
-    <link rel="prev" title="Welcome to Netmaker’s documentation!" href="index.html" />
+    <link rel="next" title="Advanced Server Installation" href="server-installation.html" />
+    <link rel="prev" title="Quick Install" href="quick-start.html" />
   
    
 
@@ -79,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.3.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -127,7 +129,7 @@
       
         <div class="md-flex__cell md-flex__cell--shrink">
           <div class="md-header-nav__source">
-            <a href="https://github.com/bashtage/sphinx-material/" title="Go to repository" class="md-source" data-md-source="github">
+            <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
 
     <div class="md-source__icon">
       <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="28" height="28">
@@ -136,7 +138,7 @@
     </div>
   
   <div class="md-source__repository">
-    Material for Sphinx
+    Netmaker
   </div>
 </a>
           </div>
@@ -165,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.3.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -177,16 +179,16 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.3.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.3.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
-      <a href="https://github.com/bashtage/sphinx-material/" title="Go to repository" class="md-source" data-md-source="github">
+      <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
 
     <div class="md-source__icon">
       <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="28" height="28">
@@ -195,7 +197,7 @@
     </div>
   
   <div class="md-source__repository">
-    Material for Sphinx
+    Netmaker
   </div>
 </a>
     </div>
@@ -207,6 +209,118 @@
     <li class="md-nav__item">
     
     
+      <a href="about.html" class="md-nav__link">About</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="about.html#what-is-netmaker" class="md-nav__link">What is Netmaker?</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="about.html#how-does-netmaker-work" class="md-nav__link">How Does Netmaker Work?</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="about.html#use-cases-for-netmaker" class="md-nav__link">Use Cases for Netmaker</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="architecture.html" class="md-nav__link">Architecture</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="architecture.html#core-concepts" class="md-nav__link">Core Concepts</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="architecture.html#components" class="md-nav__link">Components</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="architecture.html#technical-process" class="md-nav__link">Technical Process</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="architecture.html#compatible-systems-for-netclient" class="md-nav__link">Compatible Systems for Netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="architecture.html#limitations" class="md-nav__link">Limitations</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
     <input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="__toc">
     <label class="md-nav__link md-nav__link--active" for="__toc"> Getting Started </label>
     
@@ -218,42 +332,432 @@
   <ul class="md-nav__list" data-md-scrollfix="">
         <li class="md-nav__item"><a href="#getting-started--page-root" class="md-nav__link">Getting Started</a><nav class="md-nav">
               <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#use-cases" class="md-nav__link">Use Cases</a>
+        <li class="md-nav__item"><a href="#setup" class="md-nav__link">Setup</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#create-key" class="md-nav__link">Create Key</a>
+        </li></ul>
+            </nav>
         </li>
-        <li class="md-nav__item"><a href="#compatible-systems" class="md-nav__link">Compatible Systems</a>
+        <li class="md-nav__item"><a href="#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
         </li>
-        <li class="md-nav__item"><a href="#quick-start" class="md-nav__link">Quick Start</a>
+        <li class="md-nav__item"><a href="#manage-nodes" class="md-nav__link">Manage Nodes</a>
+        </li>
+        <li class="md-nav__item"><a href="#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+        </li>
+        <li class="md-nav__item"><a href="#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
         </li></ul>
             </nav>
         </li>
-    
-<li class="md-nav__item"><a class="md-nav__extra_link" href="_sources/getting-started.rst.txt">Show Source</a> </li>
-
   </ul>
 </nav>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="#use-cases" class="md-nav__link">Use Cases</a>
+      <a href="#setup" class="md-nav__link">Setup</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#docker-compose-install" class="md-nav__link">Docker Compose Install</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#linux-install-without-docker" class="md-nav__link">Linux Install without Docker</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#kubernetes-install" class="md-nav__link">Kubernetes Install</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="client-installation.html" class="md-nav__link">Client Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="client-installation.html#introduction-to-netclient" class="md-nav__link">Introduction to Netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="client-installation.html#modes-and-system-compatibility" class="md-nav__link">Modes and System Compatibility</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="client-installation.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="client-installation.html#configuration" class="md-nav__link">Configuration</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="client-installation.html#installation" class="md-nav__link">Installation</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="client-installation.html#managing-netclient" class="md-nav__link">Managing Netclient</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html" class="md-nav__link">External Clients</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="usage.html#basic" class="md-nav__link">Basic</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="usage.html#local-network" class="md-nav__link">Local Network</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="usage.html#site-to-site" class="md-nav__link">Site-to-Site</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="usage.html#dual-stack-with-ipv6" class="md-nav__link">Dual Stack with IPv6</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="usage.html#kubernetes-node-network" class="md-nav__link">Kubernetes Node Network</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="api.html" class="md-nav__link">API Reference</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="api.html#api-usage" class="md-nav__link">API Usage</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="api.html#authentication" class="md-nav__link">Authentication</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="api.html#format-of-calls-for-curl" class="md-nav__link">Format of Calls for Curl</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="api.html#api-documentation" class="md-nav__link">API Documentation</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="troubleshoot.html" class="md-nav__link">Troubleshooting</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="troubleshoot.html#common-issues" class="md-nav__link">Common Issues</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="troubleshoot.html#server" class="md-nav__link">Server</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="troubleshoot.html#ui" class="md-nav__link">UI</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="troubleshoot.html#agent" class="md-nav__link">Agent</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="troubleshoot.html#coredns" class="md-nav__link">CoreDNS</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="support.html" class="md-nav__link">Support</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="support.html#faq" class="md-nav__link">FAQ</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="support.html#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="support.html#contact" class="md-nav__link">Contact</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="contribute.html" class="md-nav__link">Contribute</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="contribute.html#submitting-an-issue" class="md-nav__link">Submitting an Issue</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="contribute.html#submitting-an-enhancement" class="md-nav__link">Submitting an Enhancement</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="contribute.html#contributing-code" class="md-nav__link">Contributing Code</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="conduct.html" class="md-nav__link">Code of Conduct</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="conduct.html#our-pledge" class="md-nav__link">Our Pledge</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="conduct.html#our-standards" class="md-nav__link">Our Standards</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="conduct.html#our-responsibilities" class="md-nav__link">Our Responsibilities</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#compatible-systems" class="md-nav__link">Compatible Systems</a>
+      <a href="conduct.html#scope" class="md-nav__link">Scope</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#quick-start" class="md-nav__link">Quick Start</a>
+      <a href="conduct.html#enforcement" class="md-nav__link">Enforcement</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="conduct.html#attribution" class="md-nav__link">Attribution</a>
       
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="license.html" class="md-nav__link">License</a>
+      
+    
     </li>
   </ul>
   
@@ -271,19 +775,22 @@
   <ul class="md-nav__list" data-md-scrollfix="">
         <li class="md-nav__item"><a href="#getting-started--page-root" class="md-nav__link">Getting Started</a><nav class="md-nav">
               <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#use-cases" class="md-nav__link">Use Cases</a>
+        <li class="md-nav__item"><a href="#setup" class="md-nav__link">Setup</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#create-key" class="md-nav__link">Create Key</a>
+        </li></ul>
+            </nav>
+        </li>
+        <li class="md-nav__item"><a href="#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
         </li>
-        <li class="md-nav__item"><a href="#compatible-systems" class="md-nav__link">Compatible Systems</a>
+        <li class="md-nav__item"><a href="#manage-nodes" class="md-nav__link">Manage Nodes</a>
         </li>
-        <li class="md-nav__item"><a href="#quick-start" class="md-nav__link">Quick Start</a>
+        <li class="md-nav__item"><a href="#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+        </li>
+        <li class="md-nav__item"><a href="#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
         </li></ul>
             </nav>
         </li>
-    
-<li class="md-nav__item"><a class="md-nav__extra_link" href="_sources/getting-started.rst.txt">Show Source</a> </li>
-
-<li id="searchbox" class="md-nav__item"></li>
-
   </ul>
 </nav>
               </div>
@@ -295,162 +802,79 @@
             
   
 <h1 id="getting-started--page-root">Getting Started<a class="headerlink" href="#getting-started--page-root" title="Permalink to this headline">¶</a></h1>
-<p>Netmaker is a tool for creating and managing virtual overlay networks. If you have servers spread across multiple locations, data centers, or clouds, this platform can make life easier. Netmaker takes all those machines and puts them on a single, secure, flat network so that they can all talk to each other easily and securely. It’s like a VPC but of arbitrary computers.</p>
-<p>Netmaker can be compared to and covers use cases similar to Tailscale, ZeroTier, or Nebula, but Netmaker does more than that, while being faster, more dynamic and more flexible.</p>
-<p>Netmaker uses kernel WireGuard to create encrypted tunnels between every node in your virtual network. Netmaker’s <cite>netclient</cite> agent is self-updating and pulls any necessary changes (such as new peers) from the main server.</p>
+<p>Once you have Netmaker installed via the <a class="reference internal" href="quick-start.html"><span class="doc">Quick Install</span></a> guide, you can use this Getting Started guide to help create and manage your first network.</p>
 
-<h2 id="use-cases">Use Cases<a class="headerlink" href="#use-cases" title="Permalink to this headline">¶</a></h2>
-<blockquote>
-<div><ol class="arabic simple">
-<li><p>Create a flat, secure network between multiple/hybrid cloud environments</p></li>
-<li><p>Integrate central and edge services</p></li>
-<li><p>Secure a home or office network while providing remote connectivity</p></li>
+<h2 id="setup">Setup<a class="headerlink" href="#setup" title="Permalink to this headline">¶</a></h2>
+<ol class="arabic simple">
+<li><p>Create your admin user, with a username and password.</p></li>
+<li><p>Login with your new user</p></li>
+<li><p>Create your first network by clicking on Create Network</p></li>
 </ol>
-<p>4. Manage cryptocurrency proof-of-stake machines
-6. Provide an additional layer of security on an existing network
-7. Encrypt Kubernetes inter-node communications
-8. Secure site-to-site connections</p>
-</div></blockquote>
-
-
-<h2 id="compatible-systems">Compatible Systems<a class="headerlink" href="#compatible-systems" title="Permalink to this headline">¶</a></h2>
-<dl class="simple">
-<dt>To manage a server automatically, Netmaker requires <strong>systemd-based linux.</strong> Compatible systems include:</dt><dd><ul class="simple">
-<li><p>Fedora</p></li>
-<li><p>Ubuntu</p></li>
-<li><p>Debian</p></li>
-<li><p>Mint</p></li>
-<li><p>SUSE</p></li>
-<li><p>RHEL</p></li>
-<li><p>Raspian.</p></li>
-<li><p>Arch</p></li>
-<li><p>CentOS</p></li>
-<li><p>CoreOS</p></li>
-</ul>
-</dd>
-<dt>To manage DNS (optional), the server must have systemd-resolved. Systems that have this enabled include:</dt><dd><ul class="simple">
-<li><p>Arch</p></li>
-<li><p>Debian</p></li>
-<li><p>Ubuntu</p></li>
-<li><p>SUSE</p></li>
+<a class="reference internal image-reference" href="_images/create-net.png"><img alt="Create Network Screen" class="align-center" src="_images/create-net.png" style="width: 80%;"/></a>
+<p>This network should have a sensible name (nodes will use it to set their interfaces).</p>
+<p>More importantly, it should have a non-overlapping, private address range.</p>
+<p>If you are running a small (less than 254 machines) network, and are unsure of which CIDR’s to use, you could consider:</p>
+<ul class="simple">
+<li><p>10.11.12.0/24</p></li>
+<li><p>10.20.30.0/24</p></li>
+<li><p>100.99.98.0/24</p></li>
 </ul>
-</dd>
-</dl>
-<p>In future releases, we will support other platforms such as Windows, MacOS, iOS, Android, and more.</p>
-<p>Video Tutorials and Articles:</p>
+<p>Once your network is created, you should see that the netmaker server has added itself to the network. From here, you can move on to adding additional nodes to the network.</p>
+<a class="reference internal image-reference" href="_images/netmaker-node.png"><img alt="Node Screen" class="align-center" src="_images/netmaker-node.png" style="width: 80%;"/></a>
 
-
-<h2 id="quick-start">Quick Start<a class="headerlink" href="#quick-start" title="Permalink to this headline">¶</a></h2>
-<p>[Intro/Overview Video Tutorial](<a class="reference external" href="https://youtu.be/PWLPT320Ybo">https://youtu.be/PWLPT320Ybo</a>)
-[Site-to-Site Video Tutorial](<a class="reference external" href="https://youtu.be/krCKBJhwwDk">https://youtu.be/krCKBJhwwDk</a>)</p>
-<p>### Note about permissions
-The default installation requires special privileges on the server side, because Netmaker will control the local kernel Wireguard. This can be turned off and run in non-privileged mode if necessary (but disables some features). For more details, see the <strong>Usage</strong> docs.</p>
-<dl class="simple">
-<dt>### Prereqs</dt><dd><ol class="arabic simple">
-<li><p>A running linux server to host Netmaker, with an IP reachable by your computers (Debian-based preferred but not required).</p></li>
-<li><p>Linux installed on the above server (Debian-based preferred but not required).</p></li>
-<li><p>Install Docker and Docker Compose if running in Docker Mode (see below).</p></li>
-<li><dl class="simple">
-<dt>System dependencies installed:</dt><dd><ul class="simple">
-<li><p>Docker (if running in default Docker mode. DO NOT use snap install for docker.)</p></li>
-<li><p>Docker Compose</p></li>
-<li><p>Wireguard + Resolvectl (if running in default Client mode)</p></li>
-</ul>
-</dd>
-</dl>
-</li>
+<h3 id="create-key">Create Key<a class="headerlink" href="#create-key" title="Permalink to this headline">¶</a></h3>
+<p>Adding nodes to the network typically requires a key.</p>
+<ol class="arabic simple">
+<li><p>Click on the ACCESS KEYS tab and select the network you created.</p></li>
+<li><p>Click ADD NEW ACCESS KEY</p></li>
+<li><p>Give it a name (ex: “mykey”) and a number of uses (ex: 25)</p></li>
+<li><p>Click CREATE KEY (<strong>Important:</strong> Do not click out of the following screen until you have saved your key details. It will appear only once.)</p></li>
+<li><p>Copy the bottom command under “Your agent install command with access token” and save it somewhere locally. E.x: <code class="docutils literal notranslate"><span class="pre">curl</span> <span class="pre">-sfL</span> <span class="pre">https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netclient-install.sh</span> <span class="pre">|</span> <span class="pre">KEY=vm3ow4thatogiwnsla3thsl3894ths</span> <span class="pre">sh</span> <span class="pre">-</span></code>.</p></li>
 </ol>
-</dd>
-</dl>
-<p>#### CoreDNS Preparation
-v0.3 introduces CoreDNS as a private nameserver. To run CoreDNS on your server host, you must disable systemd-resolved to open port 53:
-1. systemctl stop systemd-resolved
-2. systemctl disable systemd-resolved
-3. vim /etc/systemd/resolved.conf</p>
-<blockquote>
-<div><blockquote>
-<div><ul class="simple">
-<li><p>uncomment <strong>DNS=</strong> and add 8.8.8.8 or whatever is your preference</p></li>
-<li><p>uncomment <strong>DNSStubListener=</strong> and set to <strong>“no”</strong></p></li>
+<a class="reference internal image-reference" href="_images/access-key.png"><img alt="Access Key Screen" class="align-center" src="_images/access-key.png" style="width: 80%;"/></a>
+<p>You will use this command to install the netclient on your nodes. There are three different values for three different scenarios:</p>
+<ul class="simple">
+<li><p>The <strong>Access Key</strong> value is the secret string that will allow your node to authenticate with the Netmaker network. This can be used with existing netclient installations where additional configurations (such as setting the server IP manually) may be required. This is not typical. E.g. <code class="docutils literal notranslate"><span class="pre">netclient</span> <span class="pre">join</span> <span class="pre">-k</span> <span class="pre">&lt;access</span> <span class="pre">key&gt;</span> <span class="pre">-s</span> <span class="pre">grpc.myserver.com</span> <span class="pre">-p</span> <span class="pre">50051</span></code></p></li>
+<li><p>The <strong>Access Token</strong> value is a base64 encoded string that contains the server IP and grpc port, as well as the access key. This is decoded by the netclient and can be used with existing netclient installations like this: <code class="docutils literal notranslate"><span class="pre">netclient</span> <span class="pre">join</span> <span class="pre">-t</span> <span class="pre">&lt;access</span> <span class="pre">token&gt;</span></code>. You should use this method for adding a network to a node that is already on a network. For instance, Node A is in the <strong>mynet</strong> network and now you are adding it to <strong>default</strong>.</p></li>
+<li><p>The <strong>install command</strong> value is a curl command that can be run on Linux systems. It is a simple script that downloads the netclient binary and runs the install command all in one.</p></li>
 </ul>
-</div></blockquote>
-<ol class="arabic simple" start="4">
-<li><p>sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf</p></li>
+<p>Networks can also be enabled to allow nodes to sign up without keys at all. In this scenario, nodes enter a “pending state” and are not permitted to join the network until an admin approves them.</p>
+
+
+
+<h2 id="deploy-nodes">Deploy Nodes<a class="headerlink" href="#deploy-nodes" title="Permalink to this headline">¶</a></h2>
+<ol class="arabic simple" start="0">
+<li><p>Prereqisite: Every machine on which you install should have wireguard and systemd already installed.</p></li>
+<li><p>SSH to each machine</p></li>
+<li><p><code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">su</span> <span class="pre">-</span></code></p></li>
+<li><p><strong>Prerequisite Check:</strong> Every Linux machine on which you run the netclient must have WireGuard and systemd installed</p></li>
+<li><p>Run the install command, Ex: <code class="docutils literal notranslate"><span class="pre">curl</span> <span class="pre">-sfL</span> <span class="pre">https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netclient-install.sh</span> <span class="pre">|</span> <span class="pre">KEY=vm3ow4thatogiwnsla3thsl3894ths</span> <span class="pre">sh</span> <span class="pre">-</span></code></p></li>
 </ol>
-</div></blockquote>
-<p>### Launch Netmaker
-Note, this installs Netmaker with CoreDNS and a Netclient (privileged).  If you want to run the server non-privileged or without CoreDNS, see the advanced usage docs.</p>
+<p>You should get output similar to the below. The netclient retrieves local settings, submits them to the server for processing, and retrieves updated settings. Then it sets the local network configuration. For more information about this process, see the <a class="reference internal" href="client-installation.html"><span class="doc">client installation</span></a> documentation. If this process failed and you do not see your node in the console (see below), then reference the <a class="reference internal" href="troubleshoot.html"><span class="doc">troubleshooting</span></a> documentation.</p>
+<a class="reference internal image-reference" href="_images/nc-install-output.png"><img alt="Output from Netclient Install" class="align-center" src="_images/nc-install-output.png" style="width: 80%;"/></a>
+<a class="reference internal image-reference" href="_images/nm-node-success.png"><img alt="Node Success" class="align-center" src="_images/nm-node-success.png" style="width: 80%;"/></a>
+<p>Repeat the above steps for every machine you would like to add to your network. You can re-use the same install command so long as you do not run out of uses on your access key (after which it will be invalidated and deleted).</p>
+<p>Once installed on all nodes, you can test the connection by pinging the private address of any node from any other node.</p>
+<a class="reference internal image-reference" href="_images/ping-node.png"><img alt="Node Success" class="align-center" src="_images/ping-node.png" style="width: 80%;"/></a>
+
+
+<h2 id="manage-nodes">Manage Nodes<a class="headerlink" href="#manage-nodes" title="Permalink to this headline">¶</a></h2>
+<p>Your machines should now be visible in the control pane.</p>
+<a class="reference internal image-reference" href="_images/nodes.png"><img alt="Node Success" class="align-center" src="_images/nodes.png" style="width: 80%;"/></a>
+<p>You can view/modify/delete any node by selecting it in the NODES tab. For instance, you can change the name to something more sensible like “workstation” or “api server”. You can also modify network settings here, such as keys or the WireGuard port. These settings will be picked up by the node on its next check in. For more information, see Advanced Configuration in the <a class="reference internal" href="usage.html"><span class="doc">Using Netmaker</span></a> docs.</p>
+<a class="reference internal image-reference" href="_images/node-details.png"><img alt="Node Success" class="align-center" src="_images/node-details.png" style="width: 80%;"/></a>
+<p>Nodes can be added/removed/modified on the network at any time. Nodes can also be added to multiple Netmaker networks. Any changes will get picked up by any nodes on a given network, and will take aboue ~30 seconds to take effect.</p>
+
+
+<h2 id="uninstalling-the-netclient">Uninstalling the netclient<a class="headerlink" href="#uninstalling-the-netclient" title="Permalink to this headline">¶</a></h2>
 <ol class="arabic simple">
-<li><p>Clone this repo or just copy contents of “docker-compose.yml” to your Netmaker server (from prereqs).</p></li>
-<li><p>In docker-compose.yml, change BACKEND_URL to the public IP of your server.</p></li>
-<li><p>Run <cite>sudo docker-compose up -d</cite></p></li>
-<li><p>Navigate to your server’s IP in the browser and you should see the Netmaker UI asking to create a new admin user.</p></li>
-<li><p>Create a new admin user</p></li>
-<li><p>You are now ready to begin using Netmaker.</p></li>
-</ol>
-<p>### Create a Network
-You can also just use the “default” network.
-1. Click “CREATE NETWORK” in the upper left of your console
-2. Enter a valid address range, e.g. 10.11.12.0/24
-3. Enter a name such as “homenet”
-4. Additional options:</p>
-<blockquote>
-<div><ul class="simple">
-<li><p><strong>Dual Stack</strong>: Machines will recieve a private IPv6 address in addition to their IPv4 address.</p></li>
-<li><p><strong>Local:</strong> Will use local address range for endpoints instead of public. Use Case: Home or Office network where most devices do not have public IP’s. In this case you can create a gateway into the network after creating the Local Network.</p></li>
-</ul>
-</div></blockquote>
-<p>After Network creation, you can edit the network in the NETWORK DETAILS pane, modifying the address range and default options. You can also toggle on <strong>Allow Node Signup Without Keys</strong>, which makes the next step unnecessary, but allows anyone to create a node in your network, which will be cordoned in pending state.</p>
-<p>### Create Keys
-1. Click the “ACCESS KEYS” tab
-2. Click “ADD NEW ACCESSS KEY”
-3. Give your key a name and number of uses
-4. Several values will be displayed. Save these somewhere, as they will only be displayed once:</p>
-<blockquote>
-<div><ul class="simple">
-<li><p><strong>Access Key:</strong> Use only in special edge cases where server connection string must be modified</p></li>
-<li><p><strong>Access Token:</strong> Use on machines that already have the netclient utility</p></li>
-<li><p><strong>Install Command:</strong> Use on machines that do not have the netclient utility</p></li>
-</ul>
-</div></blockquote>
-<p>### Install Agent:
-For machines <strong>without</strong> netclient, run the install command (from above): <cite>curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.3/netclient-install.sh | KEY=&lt;your access key&gt; sh -</cite>
-For machines <strong>with</strong> netclient run the following (with access token from above): <cite>sudo netclient -c install -t &lt;access token&gt;</cite>
-For networks with <strong>manual signup</strong> enabled (see above), install using the network name: <cite>sudo netclient -c install -n &lt;network name&gt;</cite></p>
-<p>### Manage Nodes
-Your machines should now be visible in the control pane.
-<strong>Modify nodes:</strong> Click the pencil icon in the NODES pane to modify details like WireGuard port, address, and node name. You can also <strong>DELETE</strong> nodes here and they will lose network access.
-<strong>Approve nodes:</strong> If a node is in pending state (signed up without key), you can approve it. An icon will appear for pending nodes that need approval.</p>
-<p><strong>Gateway Mode:</strong> Click the Gateway icon to enable gateway mode on a given node. A popup will allow you to choose an existing network, or enter a custom address range.
-<em>Example: You create a network in netmaker called Homenet. It has several machines on your home server. You create another network called Cloudnet. It has several machines in AWS. You have one server (server X) which is added to both networks. On Cloudnet, you make Server X a gateway to Homenet. Now, the cloudnet machines have access to your homenet machines. via  Server X.</em></p>
-<p><em>On Homenet, you add Server Y, a machine in AWS, and make it a gateway to a custom address range 172.16.0.0/16. The machines on your home network now have access to any AWS machines in that address range via Server Y</em></p>
-<p>### Manage DNS
-On the DNS tab you can create custom DNS entries for a given network.</p>
-<blockquote>
-<div><ol class="arabic simple">
-<li><p>All dns entries will be <em>postfixed</em> with a private TLD of the network name, for example, “.mynet”</p></li>
-<li><p>Default DNS is created for node name + TLD, for instance, node-c42wt.mynet. This is not editable.</p></li>
-<li><dl class="simple">
-<dt>Click ADD ENTRY to add custom DNS</dt><dd><ul class="simple">
-<li><p>You can click CHOOSE NODE to direct DNS to a specific node in the network</p></li>
-<li><p>You can also specify any custom address you would like, which can be outside the network (for instance, the IP for google.com)</p></li>
-<li><p>Add a dns entry name, which will be postfixed with the network TLD. E.g. if you enter “privateapi.com”, it will become “privateapi.com.networkname”</p></li>
-</ul>
-</dd>
-</dl>
-</li>
+<li><p>To remove your nodes from the default network, run the following on each node: <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">netclient</span> <span class="pre">leave</span> <span class="pre">-n</span> <span class="pre">default</span></code></p></li>
+<li><p>To remove the netclient entirely from each node, run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">rm</span> <span class="pre">-rf</span> <span class="pre">/etc/netclient</span></code> (after running the first step)</p></li>
 </ol>
-</div></blockquote>
-<p>### Uninstalling Client
-To uninstall the client from a network: <cite>sudo netclient -c remove -n &lt; networkname &gt;</cite>
-To uninstall entirely, run the above for each network,  and then run <cite>sudo rm -rf /etc/netclient</cite></p>
-<p>### Uninstralling Netmaker
-To uninstall the netmaker server, simply run <cite>docker-compose down</cite></p>
-<p>#### LICENSE</p>
-<p>Netmaker’s source code and all artifacts in this repository are freely available. All versions are published under the Server Side Public License (SSPL), version 1, which can be found here: [LICENSE.txt](./LICENSE.txt).</p>
-<p>#### CONTACT</p>
-<p>Email: <a class="reference external" href="mailto:alex%40gravitl.com">alex<span>@</span>gravitl<span>.</span>com</a>
-Discord: <a class="reference external" href="https://discord.gg/zRb9Vfhk8A">https://discord.gg/zRb9Vfhk8A</a></p>
+
+
+<h2 id="uninstalling-netmaker">Uninstalling Netmaker<a class="headerlink" href="#uninstalling-netmaker" title="Permalink to this headline">¶</a></h2>
+<p>To uninstall Netmaker from the server, simply run <code class="docutils literal notranslate"><span class="pre">docker-compose</span> <span class="pre">down</span></code> or <code class="docutils literal notranslate"><span class="pre">docker-compose</span> <span class="pre">down</span> <span class="pre">--volumes</span></code> to remove the docker volumes for a future installation.</p>
 
 
 
@@ -464,7 +888,7 @@ Discord: <a class="reference external" href="https://discord.gg/zRb9Vfhk8A">http
     <div class="md-footer-nav">
       <nav class="md-footer-nav__inner md-grid">
           
-            <a href="index.html" title="Welcome to Netmaker’s documentation!"
+            <a href="quick-start.html" title="Quick Install"
                class="md-flex md-footer-nav__link md-footer-nav__link--prev"
                rel="prev">
               <div class="md-flex__cell md-flex__cell--shrink">
@@ -473,11 +897,22 @@ Discord: <a class="reference external" href="https://discord.gg/zRb9Vfhk8A">http
               <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
                 <span class="md-flex__ellipsis">
                   <span
-                      class="md-footer-nav__direction"> Previous </span> Welcome to Netmaker’s documentation! </span>
+                      class="md-footer-nav__direction"> Previous </span> Quick Install </span>
               </div>
             </a>
           
           
+            <a href="server-installation.html" title="Advanced Server Installation"
+               class="md-flex md-footer-nav__link md-footer-nav__link--next"
+               rel="next">
+            <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title"><span
+                class="md-flex__ellipsis"> <span
+                class="md-footer-nav__direction"> Next </span> Advanced Server Installation </span>
+            </div>
+            <div class="md-flex__cell md-flex__cell--shrink"><i
+                class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
+            </div>
+          
         </a>
         
       </nav>

+ 70 - 72
docs/_build/html/index.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Welcome to the Netmaker Documentation &#8212; Netmaker 0.5 documentation</title>
+    <title>Welcome to the Netmaker Documentation &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -80,7 +80,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="#" title="Netmaker 0.5 documentation"
+        <a href="#" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -166,7 +166,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="#" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="#" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -178,13 +178,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="#" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="#" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="#"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -278,61 +278,82 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
     </li></ul>
@@ -341,26 +362,26 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      <a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      <a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
       
     
     </li>
@@ -388,7 +409,7 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
     </li></ul>
@@ -454,53 +475,32 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
-    </li></ul>
-    
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
-      <ul class="md-nav__list"> 
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
-      
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#basic" class="md-nav__link">Basic</a>
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#local-network" class="md-nav__link">Local Network</a>
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#site-to-site" class="md-nav__link">Site-to-Site</a>
-      
+    </li></ul>
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#dual-stack-with-ipv6" class="md-nav__link">Dual Stack with IPv6</a>
-      
-    
-    </li>
+      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
+      <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="usage.html#kubernetes-node-network" class="md-nav__link">Kubernetes Node Network</a>
+      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
       
     
     </li></ul>
@@ -594,13 +594,6 @@
       <a href="support.html#faq" class="md-nav__link">FAQ</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="support.html#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a>
-      
-    
     </li>
     <li class="md-nav__item">
     
@@ -789,15 +782,24 @@
 <p>A quick start guide to getting up and running with Netmaker and WireGuard as quickly as possible.</p>
 <div class="toctree-wrapper compound">
 <ul>
-<li class="toctree-l1"><a class="reference internal" href="quick-start.html">Quick Start</a><ul>
-<li class="toctree-l2"><a class="reference internal" href="quick-start.html#introduction">Introduction</a></li>
-<li class="toctree-l2"><a class="reference internal" href="quick-start.html#prerequisites">Prerequisites</a></li>
-<li class="toctree-l2"><a class="reference internal" href="quick-start.html#install">Install</a></li>
-<li class="toctree-l2"><a class="reference internal" href="quick-start.html#setup">Setup</a></li>
-<li class="toctree-l2"><a class="reference internal" href="quick-start.html#deploy-nodes">Deploy Nodes</a></li>
-<li class="toctree-l2"><a class="reference internal" href="quick-start.html#manage-nodes">Manage Nodes</a></li>
-<li class="toctree-l2"><a class="reference internal" href="quick-start.html#uninstalling-the-netclient">Uninstalling the netclient</a></li>
-<li class="toctree-l2"><a class="reference internal" href="quick-start.html#uninstralling-netmaker">Uninstralling Netmaker</a></li>
+<li class="toctree-l1"><a class="reference internal" href="quick-start.html">Quick Install</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="quick-start.html#introduction">0. Introduction</a></li>
+<li class="toctree-l2"><a class="reference internal" href="quick-start.html#prerequisites">1. Prerequisites</a></li>
+<li class="toctree-l2"><a class="reference internal" href="quick-start.html#install-dependencies">2. Install Dependencies</a></li>
+<li class="toctree-l2"><a class="reference internal" href="quick-start.html#prepare-vm">3. Prepare VM</a></li>
+<li class="toctree-l2"><a class="reference internal" href="quick-start.html#install-netmaker">4. Install Netmaker</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="toctree-wrapper compound">
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="getting-started.html">Getting Started</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="getting-started.html#setup">Setup</a></li>
+<li class="toctree-l2"><a class="reference internal" href="getting-started.html#deploy-nodes">Deploy Nodes</a></li>
+<li class="toctree-l2"><a class="reference internal" href="getting-started.html#manage-nodes">Manage Nodes</a></li>
+<li class="toctree-l2"><a class="reference internal" href="getting-started.html#uninstalling-the-netclient">Uninstalling the netclient</a></li>
+<li class="toctree-l2"><a class="reference internal" href="getting-started.html#uninstalling-netmaker">Uninstalling Netmaker</a></li>
 </ul>
 </li>
 </ul>
@@ -808,14 +810,14 @@
 <p>A detailed guide to installing the Netmaker server (API, DB, UI, DNS), and configuration options.</p>
 <div class="toctree-wrapper compound">
 <ul>
-<li class="toctree-l1"><a class="reference internal" href="server-installation.html">Server Installation</a><ul>
-<li class="toctree-l2"><a class="reference internal" href="server-installation.html#notes-on-optional-features">Notes on Optional Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="server-installation.html">Advanced Server Installation</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="server-installation.html#system-compatibility">System Compatibility</a></li>
-<li class="toctree-l2"><a class="reference internal" href="server-installation.html#dns-mode-prereqisite-setup">DNS Mode Prereqisite Setup</a></li>
+<li class="toctree-l2"><a class="reference internal" href="server-installation.html#server-configuration-reference">Server Configuration Reference</a></li>
+<li class="toctree-l2"><a class="reference internal" href="server-installation.html#dns-mode-setup">DNS Mode Setup</a></li>
 <li class="toctree-l2"><a class="reference internal" href="server-installation.html#docker-compose-install">Docker Compose Install</a></li>
 <li class="toctree-l2"><a class="reference internal" href="server-installation.html#linux-install-without-docker">Linux Install without Docker</a></li>
 <li class="toctree-l2"><a class="reference internal" href="server-installation.html#kubernetes-install">Kubernetes Install</a></li>
-<li class="toctree-l2"><a class="reference internal" href="server-installation.html#configuration-reference">Configuration Reference</a></li>
+<li class="toctree-l2"><a class="reference internal" href="server-installation.html#nginx-reverse-proxy-setup-with-https">Nginx Reverse Proxy Setup with https</a></li>
 </ul>
 </li>
 </ul>
@@ -845,6 +847,8 @@
 <ul>
 <li class="toctree-l1"><a class="reference internal" href="external-clients.html">External Clients</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="external-clients.html#introduction">Introduction</a></li>
+<li class="toctree-l2"><a class="reference internal" href="external-clients.html#configuring-an-ingress-gateway">Configuring an Ingress Gateway</a></li>
+<li class="toctree-l2"><a class="reference internal" href="external-clients.html#adding-clients-to-a-gateway">Adding Clients to a Gateway</a></li>
 </ul>
 </li>
 </ul>
@@ -857,11 +861,6 @@
 <ul>
 <li class="toctree-l1"><a class="reference internal" href="usage.html">Using Netmaker</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="usage.html#external-tutorials">External Tutorials</a></li>
-<li class="toctree-l2"><a class="reference internal" href="usage.html#basic">Basic</a></li>
-<li class="toctree-l2"><a class="reference internal" href="usage.html#local-network">Local Network</a></li>
-<li class="toctree-l2"><a class="reference internal" href="usage.html#site-to-site">Site-to-Site</a></li>
-<li class="toctree-l2"><a class="reference internal" href="usage.html#dual-stack-with-ipv6">Dual Stack with IPv6</a></li>
-<li class="toctree-l2"><a class="reference internal" href="usage.html#kubernetes-node-network">Kubernetes Node Network</a></li>
 </ul>
 </li>
 </ul>
@@ -900,7 +899,6 @@
 <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#issues-bugs-and-feature-requests">Issues, Bugs, and Feature Requests</a></li>
 <li class="toctree-l2"><a class="reference internal" href="support.html#contact">Contact</a></li>
 </ul>
 </li>

+ 54 - 19
docs/_build/html/license.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>License &#8212; Netmaker 0.5 documentation</title>
+    <title>License &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -80,7 +80,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -166,7 +166,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -178,13 +178,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -278,81 +278,95 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
-    </li></ul>
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
-      <ul class="md-nav__list"> 
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
       <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
@@ -391,6 +405,13 @@
       <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
+      
+    
     </li></ul>
     
     </li>
@@ -454,6 +475,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>

BIN
docs/_build/html/objects.inv


+ 230 - 121
docs/_build/html/quick-start.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Quick Start &#8212; Netmaker 0.5 documentation</title>
+    <title>Quick Install &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -56,7 +56,7 @@
     <link rel="author" title="About these documents" href="about.html" />
     <link rel="index" title="Index" href="genindex.html" />
     <link rel="search" title="Search" href="search.html" />
-    <link rel="next" title="Server Installation" href="server-installation.html" />
+    <link rel="next" title="Getting Started" href="getting-started.html" />
     <link rel="prev" title="Architecture" href="architecture.html" />
   
    
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -94,7 +94,7 @@
       <div class="md-flex__cell md-flex__cell--stretch">
         <div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
           <span class="md-header-nav__topic">Netmaker Docs</span>
-          <span class="md-header-nav__topic"> Quick Start </span>
+          <span class="md-header-nav__topic"> Quick Install </span>
         </div>
       </div>
       <div class="md-flex__cell md-flex__cell--shrink">
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -280,35 +280,47 @@
     
     
     <input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="__toc">
-    <label class="md-nav__link md-nav__link--active" for="__toc"> Quick Start </label>
+    <label class="md-nav__link md-nav__link--active" for="__toc"> Quick Install </label>
     
-      <a href="#" class="md-nav__link md-nav__link--active">Quick Start</a>
+      <a href="#" class="md-nav__link md-nav__link--active">Quick Install</a>
       
         
 <nav class="md-nav md-nav--secondary">
     <label class="md-nav__title" for="__toc">Contents</label>
   <ul class="md-nav__list" data-md-scrollfix="">
-        <li class="md-nav__item"><a href="#quick-start--page-root" class="md-nav__link">Quick Start</a><nav class="md-nav">
+        <li class="md-nav__item"><a href="#quick-start--page-root" class="md-nav__link">Quick Install</a><nav class="md-nav">
               <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#introduction" class="md-nav__link">Introduction</a>
+        <li class="md-nav__item"><a href="#introduction" class="md-nav__link">0. Introduction</a>
         </li>
-        <li class="md-nav__item"><a href="#prerequisites" class="md-nav__link">Prerequisites</a>
+        <li class="md-nav__item"><a href="#prerequisites" class="md-nav__link">1. Prerequisites</a>
         </li>
-        <li class="md-nav__item"><a href="#install" class="md-nav__link">Install</a>
-        </li>
-        <li class="md-nav__item"><a href="#setup" class="md-nav__link">Setup</a><nav class="md-nav">
+        <li class="md-nav__item"><a href="#install-dependencies" class="md-nav__link">2. Install Dependencies</a><nav class="md-nav">
               <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#create-key" class="md-nav__link">Create Key</a>
+        <li class="md-nav__item"><a href="#install-docker" class="md-nav__link">Install Docker</a>
+        </li>
+        <li class="md-nav__item"><a href="#id1" class="md-nav__link">Install Dependencies</a>
         </li></ul>
             </nav>
         </li>
-        <li class="md-nav__item"><a href="#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+        <li class="md-nav__item"><a href="#prepare-vm" class="md-nav__link">3. Prepare VM</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#prepare-domain" class="md-nav__link">Prepare Domain</a>
         </li>
-        <li class="md-nav__item"><a href="#manage-nodes" class="md-nav__link">Manage Nodes</a>
+        <li class="md-nav__item"><a href="#prepare-firewall" class="md-nav__link">Prepare Firewall</a>
         </li>
-        <li class="md-nav__item"><a href="#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+        <li class="md-nav__item"><a href="#prepare-for-dns" class="md-nav__link">Prepare for DNS</a>
         </li>
-        <li class="md-nav__item"><a href="#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+        <li class="md-nav__item"><a href="#prepare-nginx" class="md-nav__link">Prepare Nginx</a>
+        </li></ul>
+            </nav>
+        </li>
+        <li class="md-nav__item"><a href="#install-netmaker" class="md-nav__link">4. Install Netmaker</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#prepare-templates" class="md-nav__link">Prepare Templates</a>
+        </li>
+        <li class="md-nav__item"><a href="#start-netmaker" class="md-nav__link">Start Netmaker</a>
+        </li></ul>
+            </nav>
         </li></ul>
             </nav>
         </li>
@@ -318,56 +330,77 @@
     <li class="md-nav__item">
     
     
-      <a href="#introduction" class="md-nav__link">Introduction</a>
+      <a href="#introduction" class="md-nav__link">0. Introduction</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#install" class="md-nav__link">Install</a>
+      <a href="#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#setup" class="md-nav__link">Setup</a>
+      <a href="#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
     </li></ul>
@@ -376,26 +409,26 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      <a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      <a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
       
     
     </li>
@@ -423,7 +456,7 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
     </li></ul>
@@ -489,6 +522,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>
@@ -744,27 +791,39 @@
 <nav class="md-nav md-nav--secondary">
     <label class="md-nav__title" for="__toc">Contents</label>
   <ul class="md-nav__list" data-md-scrollfix="">
-        <li class="md-nav__item"><a href="#quick-start--page-root" class="md-nav__link">Quick Start</a><nav class="md-nav">
+        <li class="md-nav__item"><a href="#quick-start--page-root" class="md-nav__link">Quick Install</a><nav class="md-nav">
               <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#introduction" class="md-nav__link">Introduction</a>
-        </li>
-        <li class="md-nav__item"><a href="#prerequisites" class="md-nav__link">Prerequisites</a>
+        <li class="md-nav__item"><a href="#introduction" class="md-nav__link">0. Introduction</a>
         </li>
-        <li class="md-nav__item"><a href="#install" class="md-nav__link">Install</a>
+        <li class="md-nav__item"><a href="#prerequisites" class="md-nav__link">1. Prerequisites</a>
         </li>
-        <li class="md-nav__item"><a href="#setup" class="md-nav__link">Setup</a><nav class="md-nav">
+        <li class="md-nav__item"><a href="#install-dependencies" class="md-nav__link">2. Install Dependencies</a><nav class="md-nav">
               <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#create-key" class="md-nav__link">Create Key</a>
+        <li class="md-nav__item"><a href="#install-docker" class="md-nav__link">Install Docker</a>
+        </li>
+        <li class="md-nav__item"><a href="#id1" class="md-nav__link">Install Dependencies</a>
         </li></ul>
             </nav>
         </li>
-        <li class="md-nav__item"><a href="#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+        <li class="md-nav__item"><a href="#prepare-vm" class="md-nav__link">3. Prepare VM</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#prepare-domain" class="md-nav__link">Prepare Domain</a>
         </li>
-        <li class="md-nav__item"><a href="#manage-nodes" class="md-nav__link">Manage Nodes</a>
+        <li class="md-nav__item"><a href="#prepare-firewall" class="md-nav__link">Prepare Firewall</a>
         </li>
-        <li class="md-nav__item"><a href="#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+        <li class="md-nav__item"><a href="#prepare-for-dns" class="md-nav__link">Prepare for DNS</a>
         </li>
-        <li class="md-nav__item"><a href="#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+        <li class="md-nav__item"><a href="#prepare-nginx" class="md-nav__link">Prepare Nginx</a>
+        </li></ul>
+            </nav>
+        </li>
+        <li class="md-nav__item"><a href="#install-netmaker" class="md-nav__link">4. Install Netmaker</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#prepare-templates" class="md-nav__link">Prepare Templates</a>
+        </li>
+        <li class="md-nav__item"><a href="#start-netmaker" class="md-nav__link">Start Netmaker</a>
+        </li></ul>
+            </nav>
         </li></ul>
             </nav>
         </li>
@@ -778,103 +837,153 @@
           <article class="md-content__inner md-typeset" role="main">
             
   
-<h1 id="quick-start--page-root">Quick Start<a class="headerlink" href="#quick-start--page-root" title="Permalink to this headline">¶</a></h1>
+<h1 id="quick-start--page-root">Quick Install<a class="headerlink" href="#quick-start--page-root" title="Permalink to this headline">¶</a></h1>
+<p>This quick start guide is an <strong>opinionated</strong> guide for getting up and running with Netmaker as quickly as possible.</p>
 
-<h2 id="introduction">Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
-<p>This is a guide to getting up and running with Netmaker as quickly as possible.</p>
-<p>By default, Netmaker ships with DNS Mode, Client Mode, and Secure GRPC enabled. However, these features require special permissions and are not necessary for a simple setup, so we are going to deploy without them. To learn more about enabling these features, check out the <a class="reference internal" href="server-installation.html"><span class="doc">installation docs</span></a>.</p>
+<h2 id="introduction">0. Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
+<p>We assume for this installation that you want all of the Netmaker features enabled, want your server to be secure, and want it to be accessible from anywhere.</p>
+<p>This instance will not be HA. However, it should comfortably handle around one hundred concurrent clients and support most use cases.</p>
+<p>If you are deploying for an enterprise use case, please contact <a class="reference external" href="mailto:info%40gravitl.com">info<span>@</span>gravitl<span>.</span>com</a> for support.</p>
+<p>By the end of this guide, you will have Netmaker installed on a public VM linked to your custom domain, secured behind an Nginx reverse proxy.</p>
+<p>If this configuration does not fit your use case, see the <a class="reference internal" href="server-installation.html"><span class="doc">Advanced Installation</span></a> docs.</p>
 
 
-<h2 id="prerequisites">Prerequisites<a class="headerlink" href="#prerequisites" title="Permalink to this headline">¶</a></h2>
-<blockquote>
-<div><ol class="arabic simple">
-<li><p>A Linux server to host Netmaker, with an external IP reachable by your nodes (will be referred to as <strong>your-host</strong> in  document).</p></li>
-<li><p>Docker and Docker Compose installed on the above server. Follow the official <a class="reference external" href="https://docs.docker.com/engine/install/">Docker instructions</a> for installing Docker and Docker Compose on your system.</p></li>
-<li><p>All network nodes should be systemd-based (see Compatibility under <a class="reference internal" href="architecture.html"><span class="doc">Architecture</span></a> docs)</p></li>
-</ol>
-</div></blockquote>
+<h2 id="prerequisites">1. Prerequisites<a class="headerlink" href="#prerequisites" title="Permalink to this headline">¶</a></h2>
+<ul class="simple">
+<li><p><strong>Virtual Machine</strong></p>
+<ul>
+<li><p>Preferably from a cloud provider (e.x: DigitalOcean, Linode, AWS, GCP, etc.)</p></li>
+<li><p>Public, static IP</p></li>
+<li><p>Min 2GB RAM, 1 CPU (4GB RAM, 2CPU preferred)</p></li>
+<li><p>5GB+ of storage</p></li>
+<li><p>Ubuntu  20.04 Installed</p></li>
+</ul>
+</li>
+<li><p><strong>Domain</strong></p>
+<ul>
+<li><p>A publicly owned domain (e.x. example.com, mysite.biz)</p></li>
+<li><p>Permission and access to modify DNS records via DNS service (e.x: Route53)</p></li>
+</ul>
+</li>
+</ul>
 
 
-<h2 id="install">Install<a class="headerlink" href="#install" title="Permalink to this headline">¶</a></h2>
-<ol class="arabic simple">
-<li><p><code class="docutils literal notranslate"><span class="pre">ssh</span> <span class="pre">root@your-host</span></code></p></li>
-<li><p><code class="docutils literal notranslate"><span class="pre">wget</span> <span class="pre">-O</span> <span class="pre">docker-compose.yml</span> <span class="pre">https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.slim.yml</span></code></p></li>
-<li><p><code class="docutils literal notranslate"><span class="pre">sed</span> <span class="pre">-i</span> <span class="pre">‘s/HOST_IP/&lt;</span> <span class="pre">Insert</span> <span class="pre">your-host</span> <span class="pre">IP</span> <span class="pre">Address</span> <span class="pre">Here</span> <span class="pre">&gt;/g’</span> <span class="pre">docker-compose.yml</span></code></p></li>
-<li><p><code class="docutils literal notranslate"><span class="pre">docker-compose</span> <span class="pre">up</span> <span class="pre">-d</span></code></p></li>
-</ol>
-<p>Navigate to the IP address of your host in the browser. You should see the below screen. If not, please see the Quick Start section of the <a class="reference internal" href="support.html"><span class="doc">troubleshooting</span></a> docs.</p>
-<a class="reference internal image-reference" href="_images/create-user.png"><img alt="Create User Screen" class="align-center" src="_images/create-user.png" style="width: 80%;"/></a>
+<h2 id="install-dependencies">2. Install Dependencies<a class="headerlink" href="#install-dependencies" title="Permalink to this headline">¶</a></h2>
+<p><code class="docutils literal notranslate"><span class="pre">ssh</span> <span class="pre">root@your-host</span></code></p>
 
+<h3 id="install-docker">Install Docker<a class="headerlink" href="#install-docker" title="Permalink to this headline">¶</a></h3>
+<p>Begin by installing the community version of Docker and docker-compose (there are issues with the snap version). You can follow the official <a class="reference external" href="https://docs.docker.com/engine/install/">Docker instructions here</a>. Or, you can use the below series of commands which should work on Ubuntu 20.04.</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">remove</span> <span class="n">docker</span> <span class="n">docker</span><span class="o">-</span><span class="n">engine</span> <span class="n">docker</span><span class="o">.</span><span class="n">io</span> <span class="n">containerd</span> <span class="n">runc</span>
+<span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">update</span>
+<span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">apt</span><span class="o">-</span><span class="n">transport</span><span class="o">-</span><span class="n">https</span> <span class="n">ca</span><span class="o">-</span><span class="n">certificates</span> <span class="n">curl</span> <span class="n">gnupg</span> <span class="n">lsb</span><span class="o">-</span><span class="n">release</span>
+<span class="n">curl</span> <span class="o">-</span><span class="n">fsSL</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">download</span><span class="o">.</span><span class="n">docker</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">linux</span><span class="o">/</span><span class="n">ubuntu</span><span class="o">/</span><span class="n">gpg</span> <span class="o">|</span> <span class="n">sudo</span> <span class="n">gpg</span> <span class="o">--</span><span class="n">dearmor</span> <span class="o">-</span><span class="n">o</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">keyrings</span><span class="o">/</span><span class="n">docker</span><span class="o">-</span><span class="n">archive</span><span class="o">-</span><span class="n">keyring</span><span class="o">.</span><span class="n">gpg</span>
+<span class="n">echo</span> <span class="s2">"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"</span> <span class="o">|</span> <span class="n">sudo</span> <span class="n">tee</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">apt</span><span class="o">/</span><span class="n">sources</span><span class="o">.</span><span class="n">list</span><span class="o">.</span><span class="n">d</span><span class="o">/</span><span class="n">docker</span><span class="o">.</span><span class="n">list</span> <span class="o">&gt;</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">null</span>
+<span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">update</span>
+<span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">docker</span><span class="o">-</span><span class="n">ce</span> <span class="n">docker</span><span class="o">-</span><span class="n">ce</span><span class="o">-</span><span class="n">cli</span> <span class="n">containerd</span><span class="o">.</span><span class="n">io</span>
+<span class="n">sudo</span> <span class="n">curl</span> <span class="o">-</span><span class="n">L</span> <span class="s2">"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)"</span> <span class="o">-</span><span class="n">o</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">docker</span><span class="o">-</span><span class="n">compose</span>
+<span class="n">sudo</span> <span class="n">chmod</span> <span class="o">+</span><span class="n">x</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">docker</span><span class="o">-</span><span class="n">compose</span>
+<span class="n">docker</span> <span class="o">--</span><span class="n">version</span>
+<span class="n">docker</span><span class="o">-</span><span class="n">compose</span> <span class="o">--</span><span class="n">version</span>
+</pre></div>
+</div>
+<p>At this point Docker should be installed.</p>
 
-<h2 id="setup">Setup<a class="headerlink" href="#setup" title="Permalink to this headline">¶</a></h2>
-<ol class="arabic simple">
-<li><p>Create your admin user, with a username and password.</p></li>
-<li><p>Login with your new user</p></li>
-<li><p>Examine the <strong>default</strong> network. Click on DEFAULT under NETWORK DETAILS</p></li>
-</ol>
-<a class="reference internal image-reference" href="_images/default-net.png"><img alt="Create User Screen" class="align-center" src="_images/default-net.png" style="width: 80%;"/></a>
-<p>This displays information about the <strong>default</strong> network, which is created on server startup. You can delete this network if you do not need it, but for standard use cases this network should be enough to get started. Nodes will get an address from the network address range (ADDRESSRANGE). If the range conflicts with a pre-existing private network on your devices, you may want to change this, or make a new network instead. Nodes will also get default settings from here for unset configurations. For instance, the DEFAULTKEEPALIVE field will set the PersistenKeepAlive for nodes.</p>
-<p>To get started quickly, we can just use the existing default network.</p>
 
-<h3 id="create-key">Create Key<a class="headerlink" href="#create-key" title="Permalink to this headline">¶</a></h3>
-<ol class="arabic simple">
-<li><p>Click on the ACCESS KEYS tab and select the DEFAULT network.</p></li>
-<li><p>Click ADD NEW ACCESS KEY</p></li>
-<li><p>Give it a name (ex: “mykey”) and a number of uses (ex: 25)</p></li>
-<li><p>Click CREATE KEY (<strong>Important:</strong> Do not click out of the following screen until you have saved your key details. It will appear only once.)</p></li>
-<li><p>Copy the bottom command under “Your agent install command with access token” and save it somewhere locally. E.x: <code class="docutils literal notranslate"><span class="pre">curl</span> <span class="pre">-sfL</span> <span class="pre">https://raw.githubusercontent.com/gravitl/netmaker/v0.3/scripts/netclient-install.sh</span> <span class="pre">|</span> <span class="pre">KEY=vm3ow4thatogiwnsla3thsl3894ths</span> <span class="pre">sh</span> <span class="pre">-</span></code></p></li>
-</ol>
-<a class="reference internal image-reference" href="_images/access-key.png"><img alt="Access Key Screen" class="align-center" src="_images/access-key.png" style="width: 80%;"/></a>
-<p>You will use this command to install the netclient on your nodes. There are three different values for three different scenarios:</p>
-<ul class="simple">
-<li><p>The <strong>Access Key</strong> value is the secret string that will allow your node to authenticate with the Netmaker network. This can be used with existing netclient installations where additional configurations (such as setting the server IP manually) may be required. This is not typical. E.g. <code class="docutils literal notranslate"><span class="pre">netclient</span> <span class="pre">-c</span> <span class="pre">install</span> <span class="pre">-k</span> <span class="pre">&lt;access</span> <span class="pre">key&gt;</span> <span class="pre">-s</span> <span class="pre">1.2.3.4</span> <span class="pre">-p</span> <span class="pre">50052</span></code></p></li>
-<li><p>The <strong>Access Token</strong> value is a base64 encoded string that contains the server IP and grpc port, as well as the access key. This is decoded by the netclient and can be used with existing netclient installations like this: <code class="docutils literal notranslate"><span class="pre">netclient</span> <span class="pre">-c</span> <span class="pre">install</span> <span class="pre">-t</span> <span class="pre">&lt;access</span> <span class="pre">token&gt;</span></code>. You should use this method for adding a network to a node that is already on a network. For instance, Node A is in the <strong>mynet</strong> network and now you are adding it to <strong>default</strong>.</p></li>
-<li><p>The <strong>install command</strong> value is a curl command that can be run on Linux systems. It is a simple script that downloads the netclient binary and runs the install command all in one.</p></li>
-</ul>
-<p>Networks can also be enabled to allow nodes to sign up without keys at all. In this scenario, nodes enter a “pending state” and are not permitted to join the network until an admin approves them.</p>
+<h3 id="id1">Install Dependencies<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h3>
+<p>In addition to Docker, this installation requires WireGuard, Nginx, and Certbot.</p>
+<p><code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">apt</span> <span class="pre">install</span> <span class="pre">wireguard</span> <span class="pre">wireguard-tools</span> <span class="pre">nginx</span> <span class="pre">certbot</span> <span class="pre">python3-certbot-nginx</span> <span class="pre">net-tools</span></code></p>
+
 
 
+<h2 id="prepare-vm">3. Prepare VM<a class="headerlink" href="#prepare-vm" title="Permalink to this headline">¶</a></h2>
 
-<h2 id="deploy-nodes">Deploy Nodes<a class="headerlink" href="#deploy-nodes" title="Permalink to this headline">¶</a></h2>
+<h3 id="prepare-domain">Prepare Domain<a class="headerlink" href="#prepare-domain" title="Permalink to this headline">¶</a></h3>
 <ol class="arabic simple">
-<li><p>SSH to each machine</p></li>
-<li><p><code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">su</span> <span class="pre">-</span></code></p></li>
-<li><p><strong>Prerequisite Check:</strong> Every Linux machine on which you run the netclient must have WireGuard and systemd installed</p></li>
+<li><p>Choose a base domain or subdomain for Netmaker. If you own <strong>example.com</strong>, this should be something like <strong>netmaker.example.com</strong></p></li>
+</ol>
+<ul class="simple">
+<li><p>You must point your wildcard domain to the public IP of your VM, e.x: <a href="#id2"><span class="problematic" id="id3">*</span></a>.example.com –&gt; &lt;your public ip&gt;</p></li>
+</ul>
+<ol class="arabic simple" start="2">
+<li><p>Add an A record pointing to your VM using your DNS service provider for <a href="#id4"><span class="problematic" id="id5">*</span></a>.netmaker.example.com (inserting your own subdomain of course).</p></li>
+<li><p>Netmaker will create three subdomains on top of this. For the example above those subdomains would be:</p></li>
 </ol>
-<blockquote>
-<div><ul class="simple">
-<li><p><code class="docutils literal notranslate"><span class="pre">which</span> <span class="pre">wg</span></code> (should show wg binary present)</p></li>
-<li><p><code class="docutils literal notranslate"><span class="pre">pidof</span> <span class="pre">systemd</span> <span class="pre">&amp;&amp;</span> <span class="pre">echo</span> <span class="pre">"systemd</span> <span class="pre">found"</span> <span class="pre">||</span> <span class="pre">echo</span> <span class="pre">"systemd</span> <span class="pre">not</span> <span class="pre">found"</span></code></p></li>
+<ul class="simple">
+<li><p>dashboard.netmaker.example.com</p></li>
+<li><p>api.netmaker.example.com</p></li>
+<li><p>grpc.netmaker.example.com</p></li>
 </ul>
-</div></blockquote>
+<p>Moving forward we will refer to your base domain using <strong>&lt;your base domain&gt;</strong>. Replace these references with your domain (e.g. netmaker.example.com).</p>
 <ol class="arabic simple" start="4">
-<li><p>Run the install command, Ex: <code class="docutils literal notranslate"><span class="pre">curl</span> <span class="pre">-sfL</span> <span class="pre">https://raw.githubusercontent.com/gravitl/netmaker/v0.5/scripts/netclient-install.sh</span> <span class="pre">|</span> <span class="pre">KEY=vm3ow4thatogiwnsla3thsl3894ths</span> <span class="pre">sh</span> <span class="pre">-</span></code></p></li>
+<li><p><code class="docutils literal notranslate"><span class="pre">nslookup</span> <span class="pre">host.&lt;your</span> <span class="pre">base</span> <span class="pre">domain&gt;</span></code> (inserting your domain) should now return the IP of your VM.</p></li>
+<li><p>Generate SSL Certificates using certbot:</p></li>
 </ol>
-<p>You should get output similar to the below. The netclient retrieves local settings, submits them to the server for processing, and retrieves updated settings. Then it sets the local network configuration. For more information about this process, see the <a class="reference internal" href="client-installation.html"><span class="doc">client installation</span></a> documentation. If this process failed and you do not see your node in the console (see below), then reference the <a class="reference internal" href="troubleshoot.html"><span class="doc">troubleshooting</span></a> documentation.</p>
-<a class="reference internal image-reference" href="_images/nc-install-output.png"><img alt="Output from Netclient Install" class="align-center" src="_images/nc-install-output.png" style="width: 80%;"/></a>
-<a class="reference internal image-reference" href="_images/nm-node-success.png"><img alt="Node Success" class="align-center" src="_images/nm-node-success.png" style="width: 80%;"/></a>
-<p>Repeat the above steps for every machine you would like to add to your network. You can re-use the same install command so long as you do not run out of uses on your access key (after which it will be invalidated and deleted).</p>
-<p>Once installed on all nodes, you can test the connection by pinging the private address of any node from any other node.</p>
-<a class="reference internal image-reference" href="_images/ping-node.png"><img alt="Node Success" class="align-center" src="_images/ping-node.png" style="width: 80%;"/></a>
+<p><code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">certbot</span> <span class="pre">certonly</span> <span class="pre">--manual</span> <span class="pre">--preferred-challenges=dns</span> <span class="pre">--email</span> <span class="pre">[email protected]</span> <span class="pre">--server</span> <span class="pre">https://acme-v02.api.letsencrypt.org/directory</span> <span class="pre">--agree-tos</span> <span class="pre">--manual-public-ip-logging-ok</span> <span class="pre">-d</span> <span class="pre">"*.&lt;your</span> <span class="pre">base</span> <span class="pre">domain&gt;"</span></code></p>
+<p>The above command (using your domain instead of &lt;your base domain&gt;), will prompt you to enter a TXT record in your DNS service provider. Do this, and <strong>wait one  minute</strong> before clicking enter, or it may fail and you will have to run the command again.</p>
 
 
-<h2 id="manage-nodes">Manage Nodes<a class="headerlink" href="#manage-nodes" title="Permalink to this headline">¶</a></h2>
-<p>Your machines should now be visible in the control pane.</p>
-<a class="reference internal image-reference" href="_images/nodes.png"><img alt="Node Success" class="align-center" src="_images/nodes.png" style="width: 80%;"/></a>
-<p>You can view/modify/delete any node by selecting it in the NODES tab. For instance, you can change the name to something more sensible like “workstation” or “api server”. You can also modify network settings here, such as keys or the WireGuard port. These settings will be picked up by the node on its next check in. For more information, see Advanced Configuration in the <a class="reference internal" href="usage.html"><span class="doc">Using Netmaker</span></a> docs.</p>
-<a class="reference internal image-reference" href="_images/node-details.png"><img alt="Node Success" class="align-center" src="_images/node-details.png" style="width: 80%;"/></a>
-<p>Nodes can be added/removed/modified on the network at any time. Nodes can also be added to multiple Netmaker networks. Any changes will get picked up by any nodes on a given network, and will take aboue ~30 seconds to take effect.</p>
+<h3 id="prepare-firewall">Prepare Firewall<a class="headerlink" href="#prepare-firewall" title="Permalink to this headline">¶</a></h3>
+<p>Make sure firewall settings are appropriate for Netmaker. You need ports 53 and 443. On the server you can run:</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">ufw</span> <span class="n">allow</span> <span class="n">proto</span> <span class="n">tcp</span> <span class="kn">from</span> <span class="nn">any</span> <span class="n">to</span> <span class="nb">any</span> <span class="n">port</span> <span class="mi">443</span> <span class="o">&amp;&amp;</span> <span class="n">sudo</span> <span class="n">ufw</span> <span class="n">allow</span> <span class="n">dns</span>
+</pre></div>
+</div>
+<dl class="simple">
+<dt><strong>Based on your cloud provider, you may also need to set inbound security rules for your server. This will be dependent on your cloud provider. Be sure to check before moving on:</strong></dt><dd><ul class="simple">
+<li><p>allow 443/tcp from all</p></li>
+<li><p>allow 53/udp from all</p></li>
+</ul>
+</dd>
+</dl>
 
 
-<h2 id="uninstalling-the-netclient">Uninstalling the netclient<a class="headerlink" href="#uninstalling-the-netclient" title="Permalink to this headline">¶</a></h2>
-<ol class="arabic simple">
-<li><p>To remove your nodes from the default network, run the following on each node: <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">netclient</span> <span class="pre">leave</span> <span class="pre">-n</span> <span class="pre">default</span></code></p></li>
-<li><p>To remove the netclient entirely from each node, run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">rm</span> <span class="pre">-rf</span> <span class="pre">/etc/netclient</span></code> (after running the first step)</p></li>
-</ol>
+<h3 id="prepare-for-dns">Prepare for DNS<a class="headerlink" href="#prepare-for-dns" title="Permalink to this headline">¶</a></h3>
+<p>On Ubuntu 20.04, by default there is a service consuming port 53 related to DNS resolution. We need port 53 open in order to run our own DNS server. The below steps will disable systemd-resolved, and insert a generic DNS nameserver for local resolution.</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">systemctl</span> <span class="n">stop</span> <span class="n">systemd</span><span class="o">-</span><span class="n">resolved</span>
+<span class="n">systemctl</span> <span class="n">disable</span> <span class="n">systemd</span><span class="o">-</span><span class="n">resolved</span>
+<span class="n">vim</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">systemd</span><span class="o">/</span><span class="n">resolved</span><span class="o">.</span><span class="n">conf</span>
+  <span class="o">*</span>  <span class="n">uncomment</span> <span class="n">DNS</span> <span class="ow">and</span> <span class="n">add</span> <span class="mf">8.8.8.8</span> <span class="ow">or</span> <span class="n">whatever</span> <span class="n">reachable</span> <span class="n">nameserver</span> <span class="ow">is</span> <span class="n">your</span> <span class="n">preference</span>  <span class="o">*</span>
+  <span class="o">*</span>  <span class="n">uncomment</span> <span class="n">DNSStubListener</span> <span class="ow">and</span> <span class="nb">set</span> <span class="n">to</span> <span class="s2">"no"</span>  <span class="o">*</span>
+<span class="n">ln</span> <span class="o">-</span><span class="n">sf</span> <span class="o">/</span><span class="n">run</span><span class="o">/</span><span class="n">systemd</span><span class="o">/</span><span class="n">resolve</span><span class="o">/</span><span class="n">resolv</span><span class="o">.</span><span class="n">conf</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">resolv</span><span class="o">.</span><span class="n">conf</span>
+</pre></div>
+</div>
+
+
+<h3 id="prepare-nginx">Prepare Nginx<a class="headerlink" href="#prepare-nginx" title="Permalink to this headline">¶</a></h3>
+<p>Nginx will serve the SSL certificate with your chosen domain and forward traffic to netmaker.</p>
+<p>Get the nginx configuration file:</p>
+<p><code class="docutils literal notranslate"><span class="pre">wget</span> <span class="pre">https://raw.githubusercontent.com/gravitl/netmaker/develop/nginx/netmaker-nginx-template.conf</span></code></p>
+<p>Insert your domain in the configuration file and add to nginx:</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sed</span> <span class="o">-</span><span class="n">i</span> <span class="s1">'s/NETMAKER_BASE_DOMAIN/&lt;your base domain&gt;/g'</span> <span class="n">netmaker</span><span class="o">-</span><span class="n">nginx</span><span class="o">-</span><span class="n">template</span><span class="o">.</span><span class="n">conf</span>
+<span class="n">sudo</span> <span class="n">cp</span> <span class="n">netmaker</span><span class="o">-</span><span class="n">nginx</span><span class="o">-</span><span class="n">template</span><span class="o">.</span><span class="n">conf</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">nginx</span><span class="o">/</span><span class="n">conf</span><span class="o">.</span><span class="n">d</span><span class="o">/&lt;</span><span class="n">your</span> <span class="n">base</span> <span class="n">domain</span><span class="o">&gt;.</span><span class="n">conf</span>
+<span class="n">nginx</span> <span class="o">-</span><span class="n">t</span> <span class="o">&amp;&amp;</span> <span class="n">nginx</span> <span class="o">-</span><span class="n">s</span> <span class="n">reload</span>
+<span class="n">systemctl</span> <span class="n">restart</span> <span class="n">nginx</span>
+</pre></div>
+</div>
+
+
+
+<h2 id="install-netmaker">4. Install Netmaker<a class="headerlink" href="#install-netmaker" title="Permalink to this headline">¶</a></h2>
+
+<h3 id="prepare-templates">Prepare Templates<a class="headerlink" href="#prepare-templates" title="Permalink to this headline">¶</a></h3>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">wget</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">raw</span><span class="o">.</span><span class="n">githubusercontent</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">gravitl</span><span class="o">/</span><span class="n">netmaker</span><span class="o">/</span><span class="n">develop</span><span class="o">/</span><span class="n">compose</span><span class="o">/</span><span class="n">docker</span><span class="o">-</span><span class="n">compose</span><span class="o">.</span><span class="n">quickstart</span><span class="o">.</span><span class="n">yml</span>
+<span class="n">sed</span> <span class="o">-</span><span class="n">i</span> <span class="s1">'s/NETMAKER_BASE_DOMAIN/&lt;your base domain&gt;/g'</span> <span class="n">docker</span><span class="o">-</span><span class="n">compose</span><span class="o">.</span><span class="n">quickstart</span><span class="o">.</span><span class="n">yml</span>
+<span class="n">sed</span> <span class="o">-</span><span class="n">i</span> <span class="s1">'s/SERVER_PUBLIC_IP/&lt;your server ip&gt;/g'</span> <span class="n">docker</span><span class="o">-</span><span class="n">compose</span><span class="o">.</span><span class="n">quickstart</span><span class="o">.</span><span class="n">yml</span>
+</pre></div>
+</div>
+<p>Generate a unique master key and insert it:</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">tr</span> <span class="o">-</span><span class="n">dc</span> <span class="n">A</span><span class="o">-</span><span class="n">Za</span><span class="o">-</span><span class="n">z0</span><span class="o">-</span><span class="mi">9</span> <span class="o">&lt;/</span><span class="n">dev</span><span class="o">/</span><span class="n">urandom</span> <span class="o">|</span> <span class="n">head</span> <span class="o">-</span><span class="n">c</span> <span class="mi">30</span> <span class="p">;</span> <span class="n">echo</span> <span class="s1">''</span>
+<span class="n">sed</span> <span class="o">-</span><span class="n">i</span> <span class="s1">'s/REPLACE_MASTER_KEY/&lt;your generated key&gt;/g'</span> <span class="n">docker</span><span class="o">-</span><span class="n">compose</span><span class="o">.</span><span class="n">quickstart</span><span class="o">.</span><span class="n">yml</span>
+</pre></div>
+</div>
+
 
+<h3 id="start-netmaker">Start Netmaker<a class="headerlink" href="#start-netmaker" title="Permalink to this headline">¶</a></h3>
+<p><code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">docker-compose</span> <span class="pre">-f</span> <span class="pre">docker-compose.quickstart.yml</span> <span class="pre">up</span> <span class="pre">-d</span></code></p>
+<p>navigate to dashboard.&lt;your base domain&gt; to see your nginx instance.</p>
+<p>To troubleshoot issues, start with:</p>
+<p><code class="docutils literal notranslate"><span class="pre">docker</span> <span class="pre">logs</span> <span class="pre">netmaker</span></code></p>
+<p>Or check out the <a class="reference internal" href="troubleshoot.html"><span class="doc">troubleshoooting docs</span></a>.</p>
 
-<h2 id="uninstralling-netmaker">Uninstralling Netmaker<a class="headerlink" href="#uninstralling-netmaker" title="Permalink to this headline">¶</a></h2>
-<p>To uninstall Netmaker from the server, simply run <code class="docutils literal notranslate"><span class="pre">docker-compose</span> <span class="pre">down</span></code> or <code class="docutils literal notranslate"><span class="pre">docker-compose</span> <span class="pre">down</span> <span class="pre">--volumes</span></code> to remove the docker volumes for a future installation.</p>
 
 
 
@@ -902,12 +1011,12 @@
             </a>
           
           
-            <a href="server-installation.html" title="Server Installation"
+            <a href="getting-started.html" title="Getting Started"
                class="md-flex md-footer-nav__link md-footer-nav__link--next"
                rel="next">
             <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title"><span
                 class="md-flex__ellipsis"> <span
-                class="md-footer-nav__direction"> Next </span> Server Installation </span>
+                class="md-footer-nav__direction"> Next </span> Getting Started </span>
             </div>
             <div class="md-flex__cell md-flex__cell--shrink"><i
                 class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>

+ 46 - 53
docs/_build/html/search.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Search &#8212; Netmaker 0.5 documentation</title>
+    <title>Search &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     
@@ -85,7 +85,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -171,7 +171,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -183,13 +183,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -283,61 +283,82 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
     </li></ul>
@@ -346,26 +367,26 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      <a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      <a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
       
     
     </li>
@@ -393,7 +414,7 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
     </li></ul>
@@ -459,53 +480,32 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
-    </li></ul>
-    
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
-      <ul class="md-nav__list"> 
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
-      
-    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#basic" class="md-nav__link">Basic</a>
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#local-network" class="md-nav__link">Local Network</a>
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="usage.html#site-to-site" class="md-nav__link">Site-to-Site</a>
-      
+    </li></ul>
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="usage.html#dual-stack-with-ipv6" class="md-nav__link">Dual Stack with IPv6</a>
-      
-    
-    </li>
+      <a href="usage.html" class="md-nav__link">Using Netmaker</a>
+      <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="usage.html#kubernetes-node-network" class="md-nav__link">Kubernetes Node Network</a>
+      <a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
       
     
     </li></ul>
@@ -599,13 +599,6 @@
       <a href="support.html#faq" class="md-nav__link">FAQ</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="support.html#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a>
-      
-    
     </li>
     <li class="md-nav__item">
     

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


File diff suppressed because it is too large
+ 321 - 375
docs/_build/html/server-installation.html


+ 60 - 66
docs/_build/html/support.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Support &#8212; Netmaker 0.5 documentation</title>
+    <title>Support &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -279,61 +279,82 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
     </li></ul>
@@ -342,26 +363,26 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      <a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      <a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
       
     
     </li>
@@ -389,7 +410,7 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
     </li></ul>
@@ -455,6 +476,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>
@@ -604,24 +639,14 @@
         </li>
         <li class="md-nav__item"><a href="#how-do-i-install-the-netclient-on-x" class="md-nav__link">How do I install the Netclient on X?</a>
         </li>
-        <li class="md-nav__item"><a href="#why-mongodb-sql-is-better-and-smaller" class="md-nav__link">Why MongoDB? SQL is better and smaller.</a>
-        </li>
         <li class="md-nav__item"><a href="#is-netmaker-a-vpn-like-nordnpn" class="md-nav__link">Is Netmaker a VPN like NordNPN?</a>
         </li>
-        <li class="md-nav__item"><a href="#do-you-offer-any-paid-support" class="md-nav__link">Do you offer any paid support?</a>
+        <li class="md-nav__item"><a href="#do-you-offer-any-enterprise-support" class="md-nav__link">Do you offer any enterprise support?</a>
         </li>
         <li class="md-nav__item"><a href="#why-the-sspl-license" class="md-nav__link">Why the SSPL License?</a>
         </li></ul>
             </nav>
         </li>
-        <li class="md-nav__item"><a href="#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a><nav class="md-nav">
-              <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#issues-bugs" class="md-nav__link">Issues / Bugs</a>
-        </li>
-        <li class="md-nav__item"><a href="#feature-requests" class="md-nav__link">Feature Requests</a>
-        </li></ul>
-            </nav>
-        </li>
         <li class="md-nav__item"><a href="#contact" class="md-nav__link">Contact</a>
         </li></ul>
             </nav>
@@ -635,13 +660,6 @@
       <a href="#faq" class="md-nav__link">FAQ</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a>
-      
-    
     </li>
     <li class="md-nav__item">
     
@@ -758,24 +776,14 @@
         </li>
         <li class="md-nav__item"><a href="#how-do-i-install-the-netclient-on-x" class="md-nav__link">How do I install the Netclient on X?</a>
         </li>
-        <li class="md-nav__item"><a href="#why-mongodb-sql-is-better-and-smaller" class="md-nav__link">Why MongoDB? SQL is better and smaller.</a>
-        </li>
         <li class="md-nav__item"><a href="#is-netmaker-a-vpn-like-nordnpn" class="md-nav__link">Is Netmaker a VPN like NordNPN?</a>
         </li>
-        <li class="md-nav__item"><a href="#do-you-offer-any-paid-support" class="md-nav__link">Do you offer any paid support?</a>
+        <li class="md-nav__item"><a href="#do-you-offer-any-enterprise-support" class="md-nav__link">Do you offer any enterprise support?</a>
         </li>
         <li class="md-nav__item"><a href="#why-the-sspl-license" class="md-nav__link">Why the SSPL License?</a>
         </li></ul>
             </nav>
         </li>
-        <li class="md-nav__item"><a href="#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a><nav class="md-nav">
-              <ul class="md-nav__list">
-        <li class="md-nav__item"><a href="#issues-bugs" class="md-nav__link">Issues / Bugs</a>
-        </li>
-        <li class="md-nav__item"><a href="#feature-requests" class="md-nav__link">Feature Requests</a>
-        </li></ul>
-            </nav>
-        </li>
         <li class="md-nav__item"><a href="#contact" class="md-nav__link">Contact</a>
         </li></ul>
             </nav>
@@ -796,19 +804,14 @@
 
 <h3 id="does-will-netmaker-support-x-operating-system">Does/Will Netmaker Support X Operating System?<a class="headerlink" href="#does-will-netmaker-support-x-operating-system" title="Permalink to this headline">¶</a></h3>
 <p>Netmaker is initially available on a limited number of operating systems for good reason: Every operating system is designed differently. With a small team, we can either focus on making Netmaker do a lot on a few number of operating systems, or a little on a bunch of operating systems. We chose the first option. You can view the System Compatibility docs for more info, but in general, you should only be using Netmaker on systemd linux right now.</p>
-<p>However, as of v0.4, we will technically be able to bring any operating system into the network. This is a bit of a hack. v0.4 introduces Ingress Gateways. Think of it this way. You set up a private network. You want devices to access it. You set up a single node as an “Ingress Gateway” and generate config files for “external clients.” These clients are unmanaged and unmeshed, meaning they can access the network but only via the gateway. It also means they will not automatically account for changes to the network, and the user will have to update the configs manually.</p>
-<p>This lets us immediately “support” any device which can run WireGuard, which includes most operating systems at this point including phones and Windows.</p>
-<p>As we stabilize the design and feature set of Netmaker, we will expand the operating system support for Netclient which configures dynamic, fully-meshed devices. Expect to see updates about new OS support every few weeks, until eventually the Ingress Gateway becomes unnecessary (though you will still want it for certain use cases).</p>
+<p>However, via “external clients”, any device that supports WireGuard can be added to the network.</p>
+<p>In future iterations will expand the operating system support for Netclient, and devices that must use the “external client” feature can switch to Netclient.</p>
 
 
 <h3 id="how-do-i-install-the-netclient-on-x">How do I install the Netclient on X?<a class="headerlink" href="#how-do-i-install-the-netclient-on-x" title="Permalink to this headline">¶</a></h3>
 <p>As per the above, there are many unsupported operating systems. You are still welcome to try, it is just an executable binary file after all. If the system is unix-based and has kernel WireGuard installed, netclient may very well mesh the device into the network. However, the service likely will encounter problems retrieving updates.</p>
 
 
-<h3 id="why-mongodb-sql-is-better-and-smaller">Why MongoDB? SQL is better and smaller.<a class="headerlink" href="#why-mongodb-sql-is-better-and-smaller" title="Permalink to this headline">¶</a></h3>
-<p>We are in a phase of rapid iteration. Every week the database schema changes. MongoDB makes our development process much more flexible. That said, we agree! SQL will be better for production, and indeed, we plan to switch over to SQL before v1.0, so please be patient with the resource consumption of MongoDB for the time being; it is helping to support a rapid pace of development.</p>
-
-
 <h3 id="is-netmaker-a-vpn-like-nordnpn">Is Netmaker a VPN like NordNPN?<a class="headerlink" href="#is-netmaker-a-vpn-like-nordnpn" title="Permalink to this headline">¶</a></h3>
 <p>No. Netmaker makes Virtual Networks, which are technically VPNs, but different. It’s more like a corporate VPN, or a VPC (if you’re familiar with AWS).</p>
 <p>If you’re looking to achieve self-hosted web browsing, with functionality similar to NordVPN, ExpressVPN, Surfshark, Tunnelbear, or Private Internet Access, this is probably not the project for you. Technically, you can accomplish this with Netmaker, but it would be a little like using a all-terrain vehicle for stock car racing.</p>
@@ -819,8 +822,8 @@
 <a class="reference external" href="https://github.com/mullvad/mullvadvpn-app">https://github.com/mullvad/mullvadvpn-app</a></p>
 
 
-<h3 id="do-you-offer-any-paid-support">Do you offer any paid support?<a class="headerlink" href="#do-you-offer-any-paid-support" title="Permalink to this headline">¶</a></h3>
-<p>Not at this time, but eventually we will. If you are interested, or if you are interested in sponsoring the project generally, please contact Alex Feiszli (<a class="reference external" href="mailto:alex%40gravitl.com">alex<span>@</span>gravitl<span>.</span>com</a>).</p>
+<h3 id="do-you-offer-any-enterprise-support">Do you offer any enterprise support?<a class="headerlink" href="#do-you-offer-any-enterprise-support" title="Permalink to this headline">¶</a></h3>
+<p>If you are interested in enterprise support for your project, please contact <a class="reference external" href="mailto:info%40gravitl.com">info<span>@</span>gravitl<span>.</span>com</a>.</p>
 
 
 <h3 id="why-the-sspl-license">Why the SSPL License?<a class="headerlink" href="#why-the-sspl-license" title="Permalink to this headline">¶</a></h3>
@@ -831,15 +834,6 @@
 
 
 
-<h2 id="issues-bugs-and-feature-requests">Issues, Bugs, and Feature Requests<a class="headerlink" href="#issues-bugs-and-feature-requests" title="Permalink to this headline">¶</a></h2>
-
-<h3 id="issues-bugs">Issues / Bugs<a class="headerlink" href="#issues-bugs" title="Permalink to this headline">¶</a></h3>
-
-
-<h3 id="feature-requests">Feature Requests<a class="headerlink" href="#feature-requests" title="Permalink to this headline">¶</a></h3>
-
-
-
 <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>Email: <a class="reference external" href="mailto:info%40gravitl.com">info<span>@</span>gravitl<span>.</span>com</a></p>

+ 122 - 26
docs/_build/html/troubleshoot.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Troubleshooting &#8212; Netmaker 0.5 documentation</title>
+    <title>Troubleshooting &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -279,61 +279,82 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
       
     
+    </li></ul>
+    
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
     </li></ul>
@@ -342,26 +363,26 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      <a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      <a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
       
     
     </li>
@@ -389,7 +410,7 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
     </li></ul>
@@ -455,6 +476,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>
@@ -619,13 +654,6 @@
       <a href="support.html#faq" class="md-nav__link">FAQ</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="support.html#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a>
-      
-    
     </li>
     <li class="md-nav__item">
     
@@ -761,18 +789,86 @@
 <h1 id="troubleshoot--page-root">Troubleshooting<a class="headerlink" href="#troubleshoot--page-root" title="Permalink to this headline">¶</a></h1>
 
 <h2 id="common-issues">Common Issues<a class="headerlink" href="#common-issues" title="Permalink to this headline">¶</a></h2>
+<dl class="simple">
+<dt><strong>How can I connect my Android, IOS, MacOS or Windows device to my Netmaker VPN?</strong></dt><dd><p>Currently meshing one of these devices is not supported, however it will be soon.
+For now you can connect to your VPN by making one of the nodes an Ingressgateway, then
+create an Ext Client for each device. Finally, use the official WG app or another
+WG configuration app to connect via QR or downloading the device’s WireGuard configuration.</p>
+</dd>
+<dt><strong>I’ve made changes to my nodes but the nodes themselves haven’t updated yet, why?</strong></dt><dd><p>Please allow your nodes to complete a check in or two, in order to reconfigure themselves.
+In some cases, it could take up to a minute or so.</p>
+</dd>
+<dt><strong>Do I have to use access keys to join a network?</strong></dt><dd><p>Although keys are the preferred way to join a network, Netmaker does allow for manual node sign-ups.
+Simply turn on “allow manual signups” on your network and nodes will not connect until you manually aprove each one.</p>
+</dd>
+<dt><strong>Is there a community or forum to ask questions about Netmaker?</strong></dt><dd><p>Yes, we have an active <a class="reference external" href="https://discord.gg/Pt4T9y9XK8">discord</a> community and issues on our <a class="reference external" href="https://github.com/gravitl/netmaker/issues">github</a> are answered frequently!
+You can also sign-up for updates at our <a class="reference external" href="https://gravitl.com/">gravitl site</a>!</p>
+</dd>
+</dl>
 
 
 <h2 id="server">Server<a class="headerlink" href="#server" title="Permalink to this headline">¶</a></h2>
+<dl class="simple">
+<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.
+Please refer to the quick-start guide to see!</p>
+</dd>
+<dt><strong>Can I connect multiple nodes (mesh clients) behind a single firewall/router?</strong></dt><dd><p>Yes! As of version 0.7 Netmaker supports UDP Hole Punching to allow this, without the use of a third party STUN server!
+Is UDP hole punching a risk for you? Well you can turn it off and make static nodes/ports for the server to refer to as well.</p>
+</dd>
+<dt><strong>What are the minimum specs to run the server?</strong></dt><dd><p>We recommend at least 1 CPU and 2 GB Memory.</p>
+</dd>
+<dt><strong>Does this support IPv6 addressing?</strong></dt><dd><p>Yes, Netmaker supports IPv6 addressing. When you create a network, just make sure to turn on Dual Stack.
+Nodes will be given IPv6 addresses along with their IPv4 address. It does not currently support IPv6 only.</p>
+</dd>
+<dt><strong>Does Netmaker support Raft Consensus?</strong></dt><dd><p>Netmaker does not directly support it, but it uses <a class="reference external" href="https://github.com/rqlite/rqlite">rqlite</a> (which supports Raft) as the database.</p>
+</dd>
+<dt><strong>How do I uninstall Netmaker?</strong></dt><dd><p>There is no official uninstall script for the Netmaker server at this time. If you followed the quick-start guide, simply run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">docker-compose</span> <span class="pre">-f</span> <span class="pre">docker-compose.quickstart.yml</span> <span class="pre">down</span> <span class="pre">--volumes</span></code>
+to completely wipe your server. Otherwise kill the running binary and it’s up to you to remove database records/volumes.</p>
+</dd>
+</dl>
 
 
 <h2 id="ui">UI<a class="headerlink" href="#ui" title="Permalink to this headline">¶</a></h2>
+<dl class="simple">
+<dt><strong>I want to make a seperate network and give my friend access to only that network.</strong></dt><dd><p>Simply navigate to the UI (as an admin account). Select users in the top left and create them an account.
+Select the network(s) to give them and they should be good to go! They are an admin of that network(s) only now.</p>
+</dd>
+<dt><strong>I’m done with an access key, can I delete it?</strong></dt><dd><p>Simply navigate to the UI (as an admin account). Select your network of interest, then the select the <code class="docutils literal notranslate"><span class="pre">Access</span> <span class="pre">Keys</span></code> tab.
+Then delete the rogue access key.</p>
+</dd>
+<dt><strong>I can’t delete my network, why?</strong></dt><dd><p>You <strong>MUST</strong> remove all nodes in a network before you can delete it.</p>
+</dd>
+<dt><strong>Can I have multiple nodes with the same name?</strong></dt><dd><p>Yes, nodes can share names without issue. It may just be harder on you to know which is which.</p>
+</dd>
+</dl>
 
 
 <h2 id="agent">Agent<a class="headerlink" href="#agent" title="Permalink to this headline">¶</a></h2>
+<dl class="simple">
+<dt><strong>How do I connect a node to my Netmaker network with Netclient?</strong></dt><dd><p>First get your access token (not just access key), then run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">netclient</span> <span class="pre">join</span> <span class="pre">-t</span> <span class="pre">&lt;access</span> <span class="pre">token&gt;</span></code>.
+<strong>NOTE:</strong> netclient may be under /etc/netclient/, i.e run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">/etc/netclient/netclient</span> <span class="pre">join</span> <span class="pre">-t</span> <span class="pre">&lt;access</span> <span class="pre">token&gt;</span></code></p>
+</dd>
+<dt><strong>How do I disconnect a node on a Netmaker network?</strong></dt><dd><p>In order to leave a Netmaker network, run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">netclient</span> <span class="pre">leave</span> <span class="pre">-n</span> <span class="pre">&lt;network-name&gt;</span></code></p>
+</dd>
+<dt><strong>How do I check the logs of my agent on a node?</strong></dt><dd><p>You will need sudo/root permissions, but you can run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">systemctl</span> <span class="pre">status</span> <span class="pre">netclient@&lt;insert</span> <span class="pre">network</span> <span class="pre">name&gt;</span></code>
+or you may also run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">journalctl</span> <span class="pre">-u</span> <span class="pre">netclient@&lt;network</span> <span class="pre">name&gt;</span></code>.
+Note for journalctl: you should hit the <code class="docutils literal notranslate"><span class="pre">end</span></code> key to get to view the most recent logs quickly or use <code class="docutils literal notranslate"><span class="pre">journalctl</span> <span class="pre">-u</span> <span class="pre">netclient@&lt;network</span> <span class="pre">name&gt;</span> <span class="pre">-f</span></code> instead.</p>
+</dd>
+<dt><strong>Can I check the configuration of my node on the node?</strong></dt><dd><p><strong>A:</strong> Yes, on the node simply run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">cat</span> <span class="pre">/etc/netclient/netconfig-&lt;network</span> <span class="pre">name&gt;</span></code> and you should see what your current configuration is!
+You can also see the current WireGuard configuration with <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">wg</span> <span class="pre">show</span></code></p>
+</dd>
+<dt><strong>I am done with the agent on my machine, can I uninstall it?</strong></dt><dd><p>Yes, on the node simply run <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">/etc/netclient/netclient</span> <span class="pre">uninstall</span></code>.</p>
+</dd>
+</dl>
 
 
 <h2 id="coredns">CoreDNS<a class="headerlink" href="#coredns" title="Permalink to this headline">¶</a></h2>
+<dl class="simple">
+<dt><strong>Is CoreDNS required to use Netmaker?</strong></dt><dd><p>CoreDNS is not required. Simply start your server with <code class="docutils literal notranslate"><span class="pre">DNS_MODE="off"</span></code>.</p>
+</dd>
+<dt><strong>What is the minimum DNS entry value I can use?</strong></dt><dd><p>Netmaker supports down to two characters for DNS names for your networks domains**</p>
+</dd>
+</dl>
 
 
 

+ 57 - 97
docs/_build/html/usage.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Using Netmaker &#8212; Netmaker 0.5 documentation</title>
+    <title>Using Netmaker &#8212; Netmaker 0.7 documentation</title>
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="stylesheet" href="_static/material.css" type="text/css" />
     <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -81,7 +81,7 @@
   <nav class="md-header-nav md-grid">
     <div class="md-flex navheader">
       <div class="md-flex__cell md-flex__cell--shrink">
-        <a href="index.html" title="Netmaker 0.5 documentation"
+        <a href="index.html" title="Netmaker 0.7 documentation"
            class="md-header-nav__button md-logo">
           
             <i class="md-icon">&#xe869</i>
@@ -167,7 +167,7 @@
   <nav class="md-tabs" data-md-component="tabs">
     <div class="md-tabs__inner md-grid">
       <ul class="md-tabs__list">
-          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.5 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.7 documentation</a></li>
       </ul>
     </div>
   </nav>
@@ -179,13 +179,13 @@
               <div class="md-sidebar__inner">
                 <nav class="md-nav md-nav--primary" data-md-level="0">
   <label class="md-nav__title md-nav__title--site" for="__drawer">
-    <a href="index.html" title="Netmaker 0.5 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.7 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.5 documentation">Netmaker Docs</a>
+       title="Netmaker 0.7 documentation">Netmaker Docs</a>
   </label>
     <div class="md-nav__source">
       <a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
@@ -279,61 +279,82 @@
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html" class="md-nav__link">Quick Start</a>
+      <a href="quick-start.html" class="md-nav__link">Quick Install</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
+      <a href="quick-start.html#introduction" class="md-nav__link">0. Introduction</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#prerequisites" class="md-nav__link">Prerequisites</a>
+      <a href="quick-start.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#install" class="md-nav__link">Install</a>
+      <a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#setup" class="md-nav__link">Setup</a>
+      <a href="quick-start.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
+      <a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
+      
+    
+    </li></ul>
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html" class="md-nav__link">Getting Started</a>
+      <ul class="md-nav__list"> 
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#setup" class="md-nav__link">Setup</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
+      <a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      <a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="quick-start.html#uninstralling-netmaker" class="md-nav__link">Uninstralling Netmaker</a>
+      <a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
       
     
     </li></ul>
@@ -342,26 +363,26 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html" class="md-nav__link">Server Installation</a>
+      <a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
       <ul class="md-nav__list"> 
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#notes-on-optional-features" class="md-nav__link">Notes on Optional Features</a>
+      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
+      <a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
       
     
     </li>
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#dns-mode-prereqisite-setup" class="md-nav__link">DNS Mode Prereqisite Setup</a>
+      <a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
       
     
     </li>
@@ -389,7 +410,7 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#configuration-reference" class="md-nav__link">Configuration Reference</a>
+      <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
     </li></ul>
@@ -455,6 +476,20 @@
       <a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
+      
+    
     </li></ul>
     
     </li>
@@ -479,16 +514,6 @@
         <li class="md-nav__item"><a href="#written-tutorials" class="md-nav__link">Written Tutorials</a>
         </li></ul>
             </nav>
-        </li>
-        <li class="md-nav__item"><a href="#basic" class="md-nav__link">Basic</a>
-        </li>
-        <li class="md-nav__item"><a href="#local-network" class="md-nav__link">Local Network</a>
-        </li>
-        <li class="md-nav__item"><a href="#site-to-site" class="md-nav__link">Site-to-Site</a>
-        </li>
-        <li class="md-nav__item"><a href="#dual-stack-with-ipv6" class="md-nav__link">Dual Stack with IPv6</a>
-        </li>
-        <li class="md-nav__item"><a href="#kubernetes-node-network" class="md-nav__link">Kubernetes Node Network</a>
         </li></ul>
             </nav>
         </li>
@@ -501,41 +526,6 @@
       <a href="#external-tutorials" class="md-nav__link">External Tutorials</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="#basic" class="md-nav__link">Basic</a>
-      
-    
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="#local-network" class="md-nav__link">Local Network</a>
-      
-    
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="#site-to-site" class="md-nav__link">Site-to-Site</a>
-      
-    
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="#dual-stack-with-ipv6" class="md-nav__link">Dual Stack with IPv6</a>
-      
-    
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="#kubernetes-node-network" class="md-nav__link">Kubernetes Node Network</a>
-      
-    
     </li></ul>
     
     </li>
@@ -627,13 +617,6 @@
       <a href="support.html#faq" class="md-nav__link">FAQ</a>
       
     
-    </li>
-    <li class="md-nav__item">
-    
-    
-      <a href="support.html#issues-bugs-and-feature-requests" class="md-nav__link">Issues, Bugs, and Feature Requests</a>
-      
-    
     </li>
     <li class="md-nav__item">
     
@@ -751,16 +734,6 @@
         <li class="md-nav__item"><a href="#written-tutorials" class="md-nav__link">Written Tutorials</a>
         </li></ul>
             </nav>
-        </li>
-        <li class="md-nav__item"><a href="#basic" class="md-nav__link">Basic</a>
-        </li>
-        <li class="md-nav__item"><a href="#local-network" class="md-nav__link">Local Network</a>
-        </li>
-        <li class="md-nav__item"><a href="#site-to-site" class="md-nav__link">Site-to-Site</a>
-        </li>
-        <li class="md-nav__item"><a href="#dual-stack-with-ipv6" class="md-nav__link">Dual Stack with IPv6</a>
-        </li>
-        <li class="md-nav__item"><a href="#kubernetes-node-network" class="md-nav__link">Kubernetes Node Network</a>
         </li></ul>
             </nav>
         </li>
@@ -791,26 +764,13 @@
 
 <h3 id="written-tutorials">Written Tutorials<a class="headerlink" href="#written-tutorials" title="Permalink to this headline">¶</a></h3>
 <ul class="simple">
-<li><p><a class="reference external" href="https://itnext.io/how-to-deploy-a-single-kubernetes-cluster-across-multiple-clouds-using-k3s-and-wireguard-a5ae176a6e81">Kubernetes Cross-cloud cluster</a>: Tutorial on setting up cross-cloud Kubernetes clusters using Netmaker.</p></li>
+<li><p><a class="reference external" href="https://itnext.io/how-to-deploy-a-single-kubernetes-cluster-across-multiple-clouds-using-k3s-and-wireguard-a5ae176a6e81">K3s Cross-cloud cluster</a>: Tutorial on setting up cross-cloud K3s clusters using Netmaker.</p></li>
+<li><p><a class="reference external" href="https://itnext.io/how-to-deploy-a-cross-cloud-kubernetes-cluster-with-built-in-disaster-recovery-bbce27fcc9d7">MicroK8s Cross-cloud cluster</a>: Tutorial on setting up cross-cloud MicroK8s clusters using Netmaker.</p></li>
+<li><p><a class="reference external" href="https://afeiszli.medium.com/how-to-enable-secure-access-to-your-hosted-services-using-netmaker-and-wireguard-1b3282d4b7aa">Secure access to private services</a>: Tutorial on setting up secure Nextcloud with Netmaker.</p></li>
 </ul>
 
 
 
-<h2 id="basic">Basic<a class="headerlink" href="#basic" title="Permalink to this headline">¶</a></h2>
-
-
-<h2 id="local-network">Local Network<a class="headerlink" href="#local-network" title="Permalink to this headline">¶</a></h2>
-
-
-<h2 id="site-to-site">Site-to-Site<a class="headerlink" href="#site-to-site" title="Permalink to this headline">¶</a></h2>
-
-
-<h2 id="dual-stack-with-ipv6">Dual Stack with IPv6<a class="headerlink" href="#dual-stack-with-ipv6" title="Permalink to this headline">¶</a></h2>
-
-
-<h2 id="kubernetes-node-network">Kubernetes Node Network<a class="headerlink" href="#kubernetes-node-network" title="Permalink to this headline">¶</a></h2>
-
-
 
 
           </article>

+ 39 - 27
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.
 
-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, MongoDB, 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.
 
 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. 
 
@@ -63,8 +63,7 @@ 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.
 
-Netmaker's netclient, the agent which controls networking on all nodes, relies heavily on systemd as of version 0.3. This reliance is being reduced but is currently a core dependency, causing most of the limitations and incompatibilities. 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.
-
+Netmaker's netclient, the agent which controls networking on all nodes, can be run as a CLI or as a system daemon. 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.
 
 Components
 ===========
@@ -82,29 +81,31 @@ Most server settings are configurable via a config file, or by environment varia
 
 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.
 
-The Netmaker server interacts with (as of v0.3) a MongoDB instance, which 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 rqlite, a distributed version of sqlite, which 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.
 
 
 Netclient
 ----------------
 
-The netclient is, at its core, a golang binary. Source code can be found in the netclient folder of the Netmaker `GitHub Repository <https://github.com/gravitl/netmaker/tree/master/netclient>`_. The binary, by itself, can be compiled for most systems. However, this binary is designed to manage a certain number of Operating Systems. As of version 0.3, it requires systemd in order to manage the host system appropriately. It may be installable, and it may even make the machine a part of the mesh network, but it will not function in entirely (see Compatible Systems for more info) without systemd.
+The netclient is, at its core, a golang binary. Source code can be found in the netclient folder of the Netmaker `GitHub Repository <https://github.com/gravitl/netmaker/tree/master/netclient>`_. The binary, by itself, can be compiled for most systems. However, this binary is designed to manage a certain number of Operating Systems. As of version 0.5, the netclient can be run as a system daemon on linux distributions with systemd, or as an "unmanaged" client on distributions without systemd.
+
+The netclient is installed via a simple bash script, which pulls the latest binary and runs 'register' and 'join' commands.
 
-The netclient is installed via a simple bash script, which pulls the latest binary and runs install command.
+The 'register' command adds a WireGuard tunnel directly to the netmaker server, for all subsequent communication.
 
-The install command registers the machine with the Netmaker server using sensible defaults, which can be overridden with a config file or environment variables. Assuming the netclient has a valid key (or the network allows manual node signup), it will be registered in the Netmaker network, which will return configuration details about how to set up the local network. 
+The 'join' command attempts to add the machine to the Netmaker network using sensible defaults, which can be overridden with a config file or environment variables. Assuming the netclient has a valid key (or the network allows manual node signup), it will be registered into the Netmaker network, and will be returned necessary configuration details for how to set up its local network. 
 
-The netclient then sets itself up in systemd, and configures WireGuard. At this point it should be part of the network.
+The netclient then sets up the systemd daemon (if running in daemon mode), and configures WireGuard. At this point it should be part of the network.
 
-On a periodic basis (systemd timer), the netclient performs a "check in." It will authenticate with the server, and check to see if anything has changed in the network. It will also post changes about its own local configuration if there. If there has been a change, the server will return new configurations and the netclient will reconfigure the network.
+If running in daemon mode, on a periodic basis (systemd timer), the netclient performs a "check in." It will authenticate with the server, and check to see if anything has changed in the network. It will also post changes about its own local configuration if there. If there has been a change, the server will return new configurations and the netclient will reconfigure the network. If not running in daemon mode, it is up to the operator to perform check ins (netclient checkin -n < network name >).
 
 The check in process is what allows Netmaker to create dynamic mesh networks. As nodes are added to, removed from, and modified on the network, other nodes are notified, and make appropriate changes.
 
 
-MongoDB
+rqlite
 --------
 
-As of v0.3, Netmaker uses MongoDB as its database, and interacts with a MongoDB instance to store and retrieve information about nodes, networks, and users. Netmaker is rapidly evolving, and MongoDB provides a flexible database structure that accelerates development. However, MongoDB is also the heaviest component of Netmaker (high cpu/memory consumption), and is set to be replaced by a lighter-weight, SQL-based database in the future.
+As of v0.7, Netmaker uses rqlite, a distributed (RAFT consensus) database, and interacts with this database to store and retrieve information about nodes, networks, and users. With the 0.7 refactor, additional database support is very easy to implement. Netmaker uses simple key value lookups to run the networks, and the database was designed to be extensible, so support for key-value stores and other SQL-based databases can be achieved by changing a single file.
 
 Netmaker UI
 ---------------
@@ -117,10 +118,20 @@ Netmaker can be used in its entirety without the UI, but the UI makes things a l
 CoreDNS
 --------
 
-v0.3 introduced the concept of private DNS management for 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.
 
 Worth considering is that CoreDNS requires port 53 on the Netmaker host system, which may cause conflicts depending on your operating system. This is explained in the :doc:`Server Installation <./server-installation>` guide.
 
+External Client
+----------------
+
+The external client is simply a manually configured WireGuard connection to your network, which Netmaker helps to manage.
+
+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. 
+
+Netmaker v0.5 introduces the "external client" to handle any devices which are not currently compatible with the netclient, including Windows, iPhone, Android, and Mac. Over time, this list will be eliminated and there may not even be a need for the external client.
+
+External clients hook into a Netmaker network via an "Ingress Gateway," which is configured for a given node and allows traffic to flow into the network.
 
 Technical Process
 ====================
@@ -132,22 +143,25 @@ Below is a high level, step-by-step overview of the flow of communications withi
 3. Both of the above requests are routed to the server via an API call from the front end
 4. Admin runs the netclient install script on any given node (machine).
 5. Netclient decodes key, which contains the GRPC server location and port
-6. Netclient retrieves/sets local information, including open ports for WireGuard, public IP, and generating key pairs for peers
-7. Netclient reaches out to GRPC server with this information, authenticating via access key.
-8. Netmaker server verifies information and creates the node, setting default values for any missing information. 
-9. Timestamp is set for the network (see #16). 
-10. Netmaker returns settings as response to netclient. Some settings may be added or modified based on the network.
-11. Netclient recieves response. If successful, it takes any additional info returned from Netmaker and configures the local system/WireGuard
-12. Netclient sends another request to Netmaker's GRPC server, this time to retrieve the peers list (all other clients in the network).
-13. Netmaker sends back peers list, including current known configurations of all nodes in network.
-14. Netclient configures WireGuard with this information. At this point, the node is fully configured as a part of the network and should be able to reach the other nodes via private address.
-15. Netclient begins daemon (system timer) to run check in's with the server. It awaits changes, reporting local changes, and retrieving changes from any other nodes in the network.
-16. Other netclients on the network, upon checking in with the Netmaker server, will see that the timestamp has updated, and they will retrieve a new peers list, completing the update cycle.
+6. Netclient uses information to register and set up WireGuard tunnel to GRPC server
+7. Netclient retrieves/sets local information, including open ports for WireGuard, public IP, and generating key pairs for peers
+8. Netclient reaches out to GRPC server with this information, authenticating via access key.
+9. Netmaker server verifies information and creates the node, setting default values for any missing information. 
+10. Timestamp is set for the network (see #16). 
+11. Netmaker returns settings as response to netclient. Some settings may be added or modified based on the network.
+12. Netclient recieves response. If successful, it takes any additional info returned from Netmaker and configures the local system/WireGuard
+13. Netclient sends another request to Netmaker's GRPC server, this time to retrieve the peers list (all other clients in the network).
+14. Netmaker sends back peers list, including current known configurations of all nodes in network.
+15. Netclient configures WireGuard with this information. At this point, the node is fully configured as a part of the network and should be able to reach the other nodes via private address.
+16. Netclient begins daemon (system timer) to run check in's with the server. It awaits changes, reporting local changes, and retrieving changes from any other nodes in the network.
+17. Other netclients on the network, upon checking in with the Netmaker server, will see that the timestamp has updated, and they will retrieve a new peers list, completing the update cycle.
 
 
 Compatible Systems for Netclient
 ==================================
 
+To manage a node manually, the Netclient can be compiled and run for most linux distibutions, with a prerequisite of WireGuard.
+
 To manage a node automatically, the Netmaker client (netclient) requires **systemd-based linux.** Compatible systems include:
         - Fedora
         - Ubuntu
@@ -169,8 +183,6 @@ To manage DNS (optional), the node must have systemd-resolved. Systems that have
 Limitations
 ===========
 
-Install limitations mostly include platform-specific limitations, such as needing systemd or systemd-resolved (see above). In addition the Netmaker platform has some additional limitations:
+Install limitations mostly include platform-specific limitations, such as needing systemd or systemd-resolved (see above). 
 
-- **Double NAT**: Netmaker is currently unable to route traffic for devices behind a "double NAT".
-- **CGNAT**: Netmaker is currently unable to route traffic for for devices behind a "carrier-grade NAT".
-- **Windows/iPhone/Android**: To reiterate the systemd limitation, Netmaker is not currently configured to support "end user" devices such as Windows desktops and phones generally. In v0.4, Netmaker will introduce external device gateways to allow this traffic (and many other sorts of devices).
+In addition the Netmaker is currently unable to route traffic for for devices behind a "carrier-grade NAT". This will be solved in a future release with the introduction of relay servers.

+ 27 - 2
docs/client-installation.rst

@@ -112,15 +112,40 @@ Managing Netclient
 Viewing Logs
 ---------------
 
+**to view current networks**
+  ``netclient list``
+
+**to tail logs**
+  ``journalctl -u netclient@<net name> -f``
+
+**to view all logs**
+  ``journalctl -u netclient@<net name>``
+
+**to get most recent log run**
+  ``systemctl status netclient@<net name>``
+
 Making Updates
 ----------------
 
+``vim /etc/netclient/netconfig-<network>``
+
+Change any of the variables in this file, and changes will be pushed to the server and processed locally on the next checkin.
+
+For instance, change the private address, endpoint, or name. See above example config file for details
+
+
 Adding/Removing Networks
 ---------------------------
 
+``netclient join -t <token>``
+
+Set any of the above flags (netclient join --help) to override settings for joining the network. 
+If a key is provided (-k), then a token is unnecessary, but grpc, server, ports, and network must all be provided via flags.
+
+
 Uninstalling
 ---------------
 
-Troubleshooting
------------------
+``netclient uninstall``
+
 

+ 1 - 1
docs/conf.py

@@ -22,7 +22,7 @@ copyright = '2021, Alex Feiszli'
 author = 'Alex Feiszli'
 
 # The full version, including alpha/beta/rc tags
-release = '0.5'
+release = '0.7'
 
 
 # -- General configuration ---------------------------------------------------

+ 10 - 0
docs/examplecode/myclient.conf

@@ -0,0 +1,10 @@
+[Interface]
+Address = 10.7.11.5/32
+PrivateKey = EJf6Yy51M/YDaZgedRpuxMmrqul35WfjmHvRZR1rQ0U=
+
+[Peer]
+PublicKey = m/RPuMVsbpgQ+RkxlgK2mG+dDFlzqn+ua2zJt8Wn7GA=
+AllowedIPs = 10.7.11.0/24
+Endpoint = 3.236.60.247:51822
+PersistentKeepalive = 20
+

+ 5 - 3
docs/examplecode/netclient-join.txt

@@ -1,3 +1,4 @@
+alex@workstation:~$ sudo netclient join --help
 NAME:
    netclient join - Join a Netmaker network.
 
@@ -6,7 +7,7 @@ USAGE:
 
 OPTIONS:
    --network value, -n value            Network to perform specified action against. (default: "all") [$NETCLIENT_NETWORK]
-   --password value, -p value           Password for authenticating with netmaker. (default: "badpassword") [$NETCLIENT_PASSWORD]
+   --password value, -p value           Password for authenticating with netmaker. [$NETCLIENT_PASSWORD]
    --endpoint value, -e value           Reachable (usually public) address for WireGuard (not the private WG address). [$NETCLIENT_ENDPOINT]
    --macaddress value, -m value         Mac Address for this machine. Used as a unique identifier within Netmaker network. [$NETCLIENT_MACADDRESS]
    --publickey value, --pubkey value    Public Key for WireGuard Interface. [$NETCLIENT_PUBLICKEY]
@@ -24,12 +25,13 @@ OPTIONS:
    --key value, -k value                Access Key for signing up machine with Netmaker server during initial 'add'. [$NETCLIENT_ACCESSKEY]
    --token value, -t value              Access Token for signing up machine with Netmaker server during initial 'add'. [$NETCLIENT_ACCESSTOKEN]
    --localrange value                   Local Range if network is local, for instance 192.168.1.0/24. [$NETCLIENT_LOCALRANGE]
-   --dns value                          Sets private dns if 'on'. Ignores if 'off'. Will retrieve from network if unset. [$NETCLIENT_DNS]
+   --dns value                          Sets private dns if 'on'. Ignores if 'off'. Will retrieve from network if unset. (default: "on") [$NETCLIENT_DNS]
    --islocal value                      Sets endpoint to local address if 'yes'. Ignores if 'no'. Will retrieve from network if unset. [$NETCLIENT_IS_LOCAL]
    --isdualstack value                  Sets ipv6 address if 'yes'. Ignores if 'no'. Will retrieve from network if unset. [$NETCLIENT_IS_DUALSTACK]
+   --udpholepunch value                 Turns on udp holepunching if 'yes'. Ignores if 'no'. Will retrieve from network if unset. [$NETCLIENT_UDP_HOLEPUNCH]
    --ipforwarding value                 Sets ip forwarding on if 'on'. Ignores if 'off'. On by default. (default: "on") [$NETCLIENT_IPFORWARDING]
    --postup value                       Sets PostUp command for WireGuard. [$NETCLIENT_POSTUP]
    --postdown value                     Sets PostDown command for WireGuard. [$NETCLIENT_POSTDOWN]
    --daemon value                       Installs daemon if 'on'. Ignores if 'off'. On by default. (default: "on") [$NETCLIENT_DAEMON]
    --roaming value                      Checks for IP changes if 'on'. Ignores if 'off'. On by default. (default: "on") [$NETCLIENT_ROAMING]
-   --help, -h                           show help (default: false)
+   --help, -h                           show help (default: false)

+ 10 - 7
docs/examplecode/netconfig-example.yml

@@ -1,4 +1,5 @@
 server:
+    corednsaddr: 147.182.251.203 # Address of CoreDNS Server (set locally with resolvectl)
     grpcaddress: 10.101.0.1:50051 # Address of GRPC Server (used for all interaction with server after registration)
     apiaddress: 1.2.3.4:8081 # Address of API Server (used only for registration/unregistration)
     accesskey: 5qKTbTgsvb45y3qyRmWft # Key used to sign up with server. Used only during registration
@@ -11,12 +12,12 @@ node:
     localaddress: 192.168.1.32 # Address on local network, used as endpoint for other local nodes for faster comms
     wgaddress: 10.7.11.2 # Private WG addres on network
     wgaddress6: "f8:34:41:77:5c:15" # Private ipv6 address if network is dual stack
-    roaming: "on" # Whether or not to grab new endpoint value automatically
-    dns: "off" # Whether or not to set local DNS based on Netmaker's Private DNS server
+    roaming: "yes" # Whether or not to grab new endpoint value automatically
+    dnson: "no" # Whether or not to set local DNS based on Netmaker's Private DNS server
     islocal: "no" # Based on network. If yes, will use local IP as endpoint.
     isdualstack: "yes" # Use IPv6 in addition to IPv4
     isingressgateway: "no" # whether or not node is an ingress gateway (will set iptables forwarding rules)
-    allowedips: "" # not currently used
+    allowedips: "" # additional IP's to add to client
     localrange: "" # local range if it's a local network. For instance, 192.168.1.0/24
     postup: "" # postup command, used by ingress/egress gateways to set iptables
     postdown: "" # postdown command, used by ingress/egress gateways to set iptables
@@ -26,7 +27,9 @@ node:
     privatekey: "" # private key, set only for changing and then will revert to blank in config
     endpoint: 78.170.22.168 # public endpoint for reaching node 
     postchanges: "false" # if true, will post and config file changes on next checkin and then revert to false
-    ipforwarding: "on" # set ip forwarding; highly recommended to leave on
-network: home # the network (duplicate of node.network)
-daemon: "on" # whether or not to manage systemd
-operatingsystem: "" # not currently in use
+    ipforwarding: "yes" # set ip forwarding; highly recommended to leave on
+    isstatic: "no" # if yes, daemon will not change pubkey, endpoint, or address
+    udpholepunch: "yes" # run UDP hole punching (will ignore port above, e.g. 51821)
+    network: home # the network (duplicate of node.network)
+daemon: "yes" # whether or not to manage systemd
+operatingsystem: "" # not currently in use

+ 40 - 0
docs/external-clients.rst

@@ -17,3 +17,43 @@ By using this method, you can hook any machine into a netmaker network that can
 It is recommended to run the netclient where compatible, but for all other cases, a machine can be configured as an external client.
 
 Important to note, an external client is not **reachable** by the network, meaning the client can establish connections to other machines, but those machines cannot independently establish a connection back. The External Client method should only be used in use cases where one wishes to access resource runnin on the virtual network, and **not** for use cases where one wishes to make a resource accessible on the network. For that, use netclient.
+
+Configuring an Ingress Gateway
+==================================
+
+External Clients must attach to an Ingress Gateway. By default, your network will not have an ingress gateway. To configure an ingress gateway, you can use any node in your network, but it should have a public IP address (not behind a NAT). Your Netmaker server can be an ingress gateway and makes for a good default choice if you are unsure of which node to select.
+
+.. image:: images/exclient1.png
+   :width: 80%
+   :alt: Gateway
+   :align: center
+
+Adding Clients to a Gateway
+=============================
+
+Once you have configured a node as a gateway, you can then add clients to that gateway. Clients will be able to access other nodes in the network just as the gateway node does.
+
+.. image:: images/exclient2.png
+   :width: 80%
+   :alt: Gateway
+   :align: center
+
+After creating a client, you can edit the name to something more logical.
+
+.. image:: images/exclient3.png
+   :width: 80%
+   :alt: Gateway
+   :align: center
+
+Then, you can either download the configuration file directly, or scan the QR code from your phone (assuming you have the WireGuard app installed). It will accept the configuration just as it would accept a typical WireGuard configuration file.
+
+.. image:: images/exclient4.png
+   :width: 80%
+   :alt: Gateway
+   :align: center
+
+Example config file: 
+
+.. literalinclude:: ./examplecode/myclient.conf
+
+Your client should now be able to access the network! A client can be invalidated at any time by simply deleting it from the UI.

+ 126 - 0
docs/getting-started.rst

@@ -0,0 +1,126 @@
+=================
+Getting Started
+=================
+
+Once you have Netmaker installed via the :doc:`Quick Install <./quick-start>` guide, you can use this Getting Started guide to help create and manage your first network.
+
+Setup
+=================
+
+#. Create your admin user, with a username and password.
+#. Login with your new user
+#. Create your first network by clicking on Create Network
+
+.. image:: images/create-net.png
+   :width: 80%
+   :alt: Create Network Screen
+   :align: center
+
+This network should have a sensible name (nodes will use it to set their interfaces).
+
+More importantly, it should have a non-overlapping, private address range. 
+
+If you are running a small (less than 254 machines) network, and are unsure of which CIDR's to use, you could consider:
+
+- 10.11.12.0/24
+- 10.20.30.0/24
+- 100.99.98.0/24
+
+Once your network is created, you should see that the netmaker server has added itself to the network. From here, you can move on to adding additional nodes to the network.
+
+.. image:: images/netmaker-node.png
+   :width: 80%
+   :alt: Node Screen
+   :align: center
+
+
+Create Key
+------------
+
+Adding nodes to the network typically requires a key.
+
+#. Click on the ACCESS KEYS tab and select the network you created.
+#. Click ADD NEW ACCESS KEY
+#. Give it a name (ex: "mykey") and a number of uses (ex: 25)
+#. Click CREATE KEY (**Important:** Do not click out of the following screen until you have saved your key details. It will appear only once.)
+#. Copy the bottom command under "Your agent install command with access token" and save it somewhere locally. E.x: ``curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netclient-install.sh | KEY=vm3ow4thatogiwnsla3thsl3894ths sh -``.
+
+.. image:: images/access-key.png
+   :width: 80%
+   :alt: Access Key Screen
+   :align: center
+
+You will use this command to install the netclient on your nodes. There are three different values for three different scenarios: 
+
+* The **Access Key** value is the secret string that will allow your node to authenticate with the Netmaker network. This can be used with existing netclient installations where additional configurations (such as setting the server IP manually) may be required. This is not typical. E.g. ``netclient join -k <access key> -s grpc.myserver.com -p 50051``
+* The **Access Token** value is a base64 encoded string that contains the server IP and grpc port, as well as the access key. This is decoded by the netclient and can be used with existing netclient installations like this: ``netclient join -t <access token>``. You should use this method for adding a network to a node that is already on a network. For instance, Node A is in the **mynet** network and now you are adding it to **default**.
+* The **install command** value is a curl command that can be run on Linux systems. It is a simple script that downloads the netclient binary and runs the install command all in one.
+  
+Networks can also be enabled to allow nodes to sign up without keys at all. In this scenario, nodes enter a "pending state" and are not permitted to join the network until an admin approves them.
+
+Deploy Nodes
+=================
+
+0. Prereqisite: Every machine on which you install should have wireguard and systemd already installed.
+
+1. SSH to each machine 
+2. ``sudo su -``
+3. **Prerequisite Check:** Every Linux machine on which you run the netclient must have WireGuard and systemd installed
+4. Run the install command, Ex: ``curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netclient-install.sh | KEY=vm3ow4thatogiwnsla3thsl3894ths sh -``
+
+You should get output similar to the below. The netclient retrieves local settings, submits them to the server for processing, and retrieves updated settings. Then it sets the local network configuration. For more information about this process, see the :doc:`client installation <./client-installation>` documentation. If this process failed and you do not see your node in the console (see below), then reference the :doc:`troubleshooting <./troubleshoot>` documentation.
+
+.. image:: images/nc-install-output.png
+   :width: 80%
+   :alt: Output from Netclient Install
+   :align: center
+
+
+.. image:: images/nm-node-success.png
+   :width: 80%
+   :alt: Node Success
+   :align: center
+
+
+Repeat the above steps for every machine you would like to add to your network. You can re-use the same install command so long as you do not run out of uses on your access key (after which it will be invalidated and deleted).
+
+Once installed on all nodes, you can test the connection by pinging the private address of any node from any other node.
+
+
+.. image:: images/ping-node.png
+   :width: 80%
+   :alt: Node Success
+   :align: center
+
+Manage Nodes
+===============
+
+Your machines should now be visible in the control pane. 
+
+.. image:: images/nodes.png
+   :width: 80%
+   :alt: Node Success
+   :align: center
+
+You can view/modify/delete any node by selecting it in the NODES tab. For instance, you can change the name to something more sensible like "workstation" or "api server". You can also modify network settings here, such as keys or the WireGuard port. These settings will be picked up by the node on its next check in. For more information, see Advanced Configuration in the :doc:`Using Netmaker <./usage>` docs.
+
+.. image:: images/node-details.png
+   :width: 80%
+   :alt: Node Success
+   :align: center
+
+
+
+Nodes can be added/removed/modified on the network at any time. Nodes can also be added to multiple Netmaker networks. Any changes will get picked up by any nodes on a given network, and will take aboue ~30 seconds to take effect.
+
+Uninstalling the netclient
+=============================
+
+1. To remove your nodes from the default network, run the following on each node: ``sudo netclient leave -n default``
+2. To remove the netclient entirely from each node, run ``sudo rm -rf /etc/netclient`` (after running the first step)
+
+Uninstalling Netmaker
+===========================
+
+To uninstall Netmaker from the server, simply run ``docker-compose down`` or ``docker-compose down --volumes`` to remove the docker volumes for a future installation.
+

BIN
docs/images/create-net.png


BIN
docs/images/exclient1.png


BIN
docs/images/exclient2.png


BIN
docs/images/exclient3.png


BIN
docs/images/exclient4.png


BIN
docs/images/netmaker-node.png


+ 5 - 0
docs/index.rst

@@ -58,6 +58,11 @@ A quick start guide to getting up and running with Netmaker and WireGuard as qui
 
    quick-start
 
+.. toctree::
+   :maxdepth: 2
+
+   getting-started
+
 Server Installation
 --------------------
 

+ 131 - 93
docs/quick-start.rst

@@ -1,137 +1,175 @@
-===========
-Quick Start
-===========
+===============
+Quick Install
+===============
+
+This quick start guide is an **opinionated** guide for getting up and running with Netmaker as quickly as possible.
+
+0. Introduction
+==================
+
+We assume for this installation that you want all of the Netmaker features enabled, want your server to be secure, and want it to be accessible from anywhere. 
+
+This instance will not be HA. However, it should comfortably handle around one hundred concurrent clients and support most use cases.
 
-Introduction
-==============
+If you are deploying for an enterprise use case, please contact [email protected] for support.
 
-This is a guide to getting up and running with Netmaker as quickly as possible. 
+By the end of this guide, you will have Netmaker installed on a public VM linked to your custom domain, secured behind an Nginx reverse proxy.
 
-By default, Netmaker ships with DNS Mode, Client Mode, and Secure GRPC enabled. However, these features require special permissions and are not necessary for a simple setup, so we are going to deploy without them. To learn more about enabling these features, check out the :doc:`installation docs <./server-installation>`.
+If this configuration does not fit your use case, see the :doc:`Advanced Installation <./server-installation>` docs. 
 
-Prerequisites
+
+
+1. Prerequisites
 ==================
- #. A Linux server to host Netmaker, with an external IP reachable by your nodes (will be referred to as **your-host** in  document).
- #. Docker and Docker Compose installed on the above server. Follow the official `Docker instructions <https://docs.docker.com/engine/install/>`_ for installing Docker and Docker Compose on your system.
- #. All network nodes should be systemd-based (see Compatibility under :doc:`Architecture <./architecture>` docs)
+-  **Virtual Machine**
+   
+   - Preferably from a cloud provider (e.x: DigitalOcean, Linode, AWS, GCP, etc.)
+   - Public, static IP 
+   - Min 2GB RAM, 1 CPU (4GB RAM, 2CPU preferred)
+   - 5GB+ of storage
+   - Ubuntu  20.04 Installed
 
-Install
-==============
-#. ``ssh root@your-host``
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.slim.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+- **Domain**
 
-Navigate to the IP address of your host in the browser. You should see the below screen. If not, please see the Quick Start section of the :doc:`troubleshooting <./support>` docs.
+  - A publicly owned domain (e.x. example.com, mysite.biz) 
+  - Permission and access to modify DNS records via DNS service (e.x: Route53)
 
-.. image:: images/create-user.png
-   :width: 80%
-   :alt: Create User Screen
-   :align: center
+2. Install Dependencies
+========================
 
-Setup
-=================
+``ssh root@your-host``
 
-#. Create your admin user, with a username and password.
-#. Login with your new user
-#. Examine the **default** network. Click on DEFAULT under NETWORK DETAILS
+Install Docker
+---------------
+Begin by installing the community version of Docker and docker-compose (there are issues with the snap version). You can follow the official `Docker instructions here <https://docs.docker.com/engine/install/>`_. Or, you can use the below series of commands which should work on Ubuntu 20.04.
 
-.. image:: images/default-net.png
-   :width: 80%
-   :alt: Create User Screen
-   :align: center
+.. code-block::
 
-This displays information about the **default** network, which is created on server startup. You can delete this network if you do not need it, but for standard use cases this network should be enough to get started. Nodes will get an address from the network address range (ADDRESSRANGE). If the range conflicts with a pre-existing private network on your devices, you may want to change this, or make a new network instead. Nodes will also get default settings from here for unset configurations. For instance, the DEFAULTKEEPALIVE field will set the PersistenKeepAlive for nodes.
+  sudo apt-get remove docker docker-engine docker.io containerd runc
+  sudo apt-get update
+  sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release
+  curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg  
+  echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
+  sudo apt-get update
+  sudo apt-get install docker-ce docker-ce-cli containerd.io
+  sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
+  sudo chmod +x /usr/local/bin/docker-compose
+  docker --version
+  docker-compose --version
 
-To get started quickly, we can just use the existing default network.
+At this point Docker should be installed.
 
-Create Key
-------------
+Install Dependencies
+-----------------------------
 
-#. Click on the ACCESS KEYS tab and select the DEFAULT network.
-#. Click ADD NEW ACCESS KEY
-#. Give it a name (ex: "mykey") and a number of uses (ex: 25)
-#. Click CREATE KEY (**Important:** Do not click out of the following screen until you have saved your key details. It will appear only once.)
-#. Copy the bottom command under "Your agent install command with access token" and save it somewhere locally. E.x: ``curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.3/scripts/netclient-install.sh | KEY=vm3ow4thatogiwnsla3thsl3894ths sh -``
+In addition to Docker, this installation requires WireGuard, Nginx, and Certbot.
 
-.. image:: images/access-key.png
-   :width: 80%
-   :alt: Access Key Screen
-   :align: center
+``sudo apt install wireguard wireguard-tools nginx certbot python3-certbot-nginx net-tools``
 
-You will use this command to install the netclient on your nodes. There are three different values for three different scenarios: 
+ 
+3. Prepare VM
+===============================
 
-* The **Access Key** value is the secret string that will allow your node to authenticate with the Netmaker network. This can be used with existing netclient installations where additional configurations (such as setting the server IP manually) may be required. This is not typical. E.g. ``netclient -c install -k <access key> -s 1.2.3.4 -p 50052``
-* The **Access Token** value is a base64 encoded string that contains the server IP and grpc port, as well as the access key. This is decoded by the netclient and can be used with existing netclient installations like this: ``netclient -c install -t <access token>``. You should use this method for adding a network to a node that is already on a network. For instance, Node A is in the **mynet** network and now you are adding it to **default**.
-* The **install command** value is a curl command that can be run on Linux systems. It is a simple script that downloads the netclient binary and runs the install command all in one.
-  
-Networks can also be enabled to allow nodes to sign up without keys at all. In this scenario, nodes enter a "pending state" and are not permitted to join the network until an admin approves them.
+Prepare Domain
+----------------------------
+1. Choose a base domain or subdomain for Netmaker. If you own **example.com**, this should be something like **netmaker.example.com**
 
-Deploy Nodes
-=================
+- You must point your wildcard domain to the public IP of your VM, e.x: *.example.com --> <your public ip>
 
-1. SSH to each machine 
-2. ``sudo su -``
-3. **Prerequisite Check:** Every Linux machine on which you run the netclient must have WireGuard and systemd installed
+2. Add an A record pointing to your VM using your DNS service provider for *.netmaker.example.com (inserting your own subdomain of course).
+3. Netmaker will create three subdomains on top of this. For the example above those subdomains would be:
 
-  * ``which wg`` (should show wg binary present)
-  * ``pidof systemd && echo "systemd found" || echo "systemd not found"``
+- dashboard.netmaker.example.com
 
-4. Run the install command, Ex: ``curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.5/scripts/netclient-install.sh | KEY=vm3ow4thatogiwnsla3thsl3894ths sh -``
+- api.netmaker.example.com
 
-You should get output similar to the below. The netclient retrieves local settings, submits them to the server for processing, and retrieves updated settings. Then it sets the local network configuration. For more information about this process, see the :doc:`client installation <./client-installation>` documentation. If this process failed and you do not see your node in the console (see below), then reference the :doc:`troubleshooting <./troubleshoot>` documentation.
+- grpc.netmaker.example.com
 
-.. image:: images/nc-install-output.png
-   :width: 80%
-   :alt: Output from Netclient Install
-   :align: center
+Moving forward we will refer to your base domain using **<your base domain>**. Replace these references with your domain (e.g. netmaker.example.com).
 
+4. ``nslookup host.<your base domain>`` (inserting your domain) should now return the IP of your VM.
 
-.. image:: images/nm-node-success.png
-   :width: 80%
-   :alt: Node Success
-   :align: center
+5. Generate SSL Certificates using certbot:
 
+``sudo certbot certonly --manual --preferred-challenges=dns --email [email protected] --server https://acme-v02.api.letsencrypt.org/directory --agree-tos --manual-public-ip-logging-ok -d "*.<your base domain>"``
 
-Repeat the above steps for every machine you would like to add to your network. You can re-use the same install command so long as you do not run out of uses on your access key (after which it will be invalidated and deleted).
+The above command (using your domain instead of <your base domain>), will prompt you to enter a TXT record in your DNS service provider. Do this, and **wait one  minute** before clicking enter, or it may fail and you will have to run the command again.
 
-Once installed on all nodes, you can test the connection by pinging the private address of any node from any other node.
+Prepare Firewall
+-----------------
 
+Make sure firewall settings are appropriate for Netmaker. You need ports 53 and 443. On the server you can run:
 
-.. image:: images/ping-node.png
-   :width: 80%
-   :alt: Node Success
-   :align: center
 
-Manage Nodes
-===============
+.. code-block::
+
+  sudo ufw allow proto tcp from any to any port 443 && sudo ufw allow dns
+
+**Based on your cloud provider, you may also need to set inbound security rules for your server. This will be dependent on your cloud provider. Be sure to check before moving on:**
+  - allow 443/tcp from all
+  - allow 53/udp from all
+
+Prepare for DNS
+----------------------------------------------------------------
+
+On Ubuntu 20.04, by default there is a service consuming port 53 related to DNS resolution. We need port 53 open in order to run our own DNS server. The below steps will disable systemd-resolved, and insert a generic DNS nameserver for local resolution.
+
+.. code-block::
+
+  systemctl stop systemd-resolved
+  systemctl disable systemd-resolved 
+  vim /etc/systemd/resolved.conf
+    *  uncomment DNS and add 8.8.8.8 or whatever reachable nameserver is your preference  *
+    *  uncomment DNSStubListener and set to "no"  *
+  ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
+
+
+Prepare Nginx
+-----------------
+
+Nginx will serve the SSL certificate with your chosen domain and forward traffic to netmaker.
+
+Get the nginx configuration file:
+
+``wget https://raw.githubusercontent.com/gravitl/netmaker/develop/nginx/netmaker-nginx-template.conf``
+
+Insert your domain in the configuration file and add to nginx:
+
+.. code-block::
+
+  sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' netmaker-nginx-template.conf
+  sudo cp netmaker-nginx-template.conf /etc/nginx/conf.d/<your base domain>.conf
+  nginx -t && nginx -s reload
+  systemctl restart nginx
+
+4. Install Netmaker
+====================
 
-Your machines should now be visible in the control pane. 
+Prepare Templates
+------------------
 
-.. image:: images/nodes.png
-   :width: 80%
-   :alt: Node Success
-   :align: center
+.. code-block::
 
-You can view/modify/delete any node by selecting it in the NODES tab. For instance, you can change the name to something more sensible like "workstation" or "api server". You can also modify network settings here, such as keys or the WireGuard port. These settings will be picked up by the node on its next check in. For more information, see Advanced Configuration in the :doc:`Using Netmaker <./usage>` docs.
+  wget https://raw.githubusercontent.com/gravitl/netmaker/develop/compose/docker-compose.quickstart.yml
+  sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' docker-compose.quickstart.yml
+  sed -i 's/SERVER_PUBLIC_IP/<your server ip>/g' docker-compose.quickstart.yml
 
-.. image:: images/node-details.png
-   :width: 80%
-   :alt: Node Success
-   :align: center
+Generate a unique master key and insert it:
 
+.. code-block::
 
+  tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo ''
+  sed -i 's/REPLACE_MASTER_KEY/<your generated key>/g' docker-compose.quickstart.yml
 
-Nodes can be added/removed/modified on the network at any time. Nodes can also be added to multiple Netmaker networks. Any changes will get picked up by any nodes on a given network, and will take aboue ~30 seconds to take effect.
+Start Netmaker
+----------------
 
-Uninstalling the netclient
-=============================
+``sudo docker-compose -f docker-compose.quickstart.yml up -d``
 
-1. To remove your nodes from the default network, run the following on each node: ``sudo netclient leave -n default``
-2. To remove the netclient entirely from each node, run ``sudo rm -rf /etc/netclient`` (after running the first step)
+navigate to dashboard.<your base domain> to see your nginx instance.
 
-Uninstralling Netmaker
-===========================
+To troubleshoot issues, start with:
 
-To uninstall Netmaker from the server, simply run ``docker-compose down`` or ``docker-compose down --volumes`` to remove the docker volumes for a future installation.
+``docker logs netmaker``
 
+Or check out the :doc:`troubleshoooting docs <./troubleshoot>`.

+ 200 - 239
docs/server-installation.rst

@@ -1,176 +1,175 @@
-====================
-Server Installation
+=================================
+Advanced Server Installation
+=================================
+
+This section outlines installing the Netmaker server, including Netmaker, Netmaker UI, rqlite, and CoreDNS
+
+System Compatibility
 ====================
 
-This section outlines installing the Netmaker server, including Netmaker, Netmaker UI, MongoDB, and CoreDNS
+Netmaker will require elevated privileges to perform network operations. Netmaker has similar limitations to :doc:`netclient <./client-installation>` (client networking agent). 
 
-Notes on Optional Features
-============================
+Typically, Netmaker is run inside of containers (Docker). To run a non-docker installation, you must run the Netmaker binary, CoreDNS binary, rqlite, and a web server directly on the host. Each of these components have their own individual requirements.
 
-There are a few key options to keep in mind when deploying Netmaker. All of the following options are enabled by default but can be disabled with a single flag at runtime (see Customization). In addition to these options, there are many more Customizable components which will be discussed later on and help to solve for special challenges and use cases.
+The quick install guide is recommended for first-time installs. 
 
-**Client Mode:** Client Mode enables Netmaker to control the underlying host server's Network. This can make management a bit easier, because Netmaker can be added into networks via a button click in the UI. This is especially useful for things like Gateways, and will open up additional options in future versions, for instance, allowing Netmaker to easily become a relay server.
+The following documents are meant for special cases like Kubernetes and LXC, or for more advanced setups. 
 
-Client Mode requires many additional privileges on the host machine, since Netmaker needs to control kernel WireGuard. Because of this, if running in Client Mode, you must run with root privileges and mount many system directories to the Netmaker container. Running without Client Mode allows you to install without privilege escalation and increases the number of compatible systems substantially.
 
-**DNS Mode:** DNS Mode enables Netmaker to write configuration files for CoreDNS, which can be set as a DNS Server for nodes. DNS Mode, paired with a CoreDNS deployment, requires use of port 53. On many linux systems (such as Ubuntu), port 53 is already in use to support local DNS, via systemd-resolved. Running in DNS Mode may require making modifications on the host machine.
+Server Configuration Reference
+==========================================
 
-**Secure GRPC**: Secure GRPC ensures all communications between nodes and the server are encrypted. Netmaker sets up a default "comms" network that exists only for nodes to connect to the server. It acts as a hub-and-spoke WireGuard network. In the below installation instructions, when port 50555 needs to be open, this is referring to the WireGuard port for Netmaker's GRPC comms. When it is port 50051, secure comms is not enabled. 
+Netmaker sets its configuration in the following order of precendence:
 
-When Secure GRPC is enabled, before any nodes can join a Netmaker network, they request to join the comms network, and are given the appropriate WireGuard configs to connect to the server. Then they are able to make requests against the private netmaker endpoint specified for the comms network (10.101.0.1 by default). If switched off, communications are not secure between the hub and nodes over GRPC (it is like http vs https), and likewise, certificates must be added to gain secure communications.
+1. Defaults
+2. Config File
+3. Environment Variables
 
-**Agent Backend:** The Agent Backend is the GRPC server (by default running on port 50051). This port is not needed for the admin server. If your use case requires special access configuration, you can run two Netmaker instances, one for the admin server, and one for node access.
+Variable Description
+----------------------
+VERBOSITY:
+    **Default:** 0
 
-**REST Backend:** Similar to the above, the REST backend runs by default on port 8081, and is used for admin API and UI access. By enabling the REST backend while disabling the Agent backend, you can separate the two functions for more restricted environments.
+    **Description:** Specify level of logging you would like on the server. Goes up to 3 for debugging.
 
 
-System Compatibility
-====================
+GRPC_SSL:
+    **Default:** "off"
 
-Both **Client Mode** and **Secure GRPC** require WireGuard to be installed on the host system, and will require elevated privileges to perform network operations..
+    **Description:** Specifies if GRPC is going over secure GRPC or SSL. This is a setting for the clients and is passed through the access token. Can be set to "on" and "off". Set to on if SSL is configured for GRPC.
 
-When both of these features are **disabled**, Netmaker can be run on any system that supports Docker, including Windows, Mac, and Linux, and other systems. With these features disabled, no special privileges are required. Netmaker will only need ports for GRPC (50051 by default), the API (8081 by default), and CoreDNS (53, if enabled).
+SERVER_API_CONN_STRING
+    **Default:** ""
 
-With Client Mode and/or Secure GRPC **enabled** (the default), Netmaker has the same limitations as the :doc:`netclient <./client-installation>` (client networking agent), because client mode just means that the Netmaker server is also running a netclient. 
+    **Description:**  Allows specification of the string used to connect to the server api. Format: IP:PORT or DOMAIN:PORT. Defaults to SERVER_HOST if not specified.
 
-These modes require privileged (root) access to the host machine. In addition, Client Mode requires multiple host directory mounts. WireGuard must be installed, the system must be systemd Linux (see :doc:`compatible systems <./architecture>` for more details).
+SERVER_GRPC_CONN_STRING
+    **Default:** ""
 
-To run a non-docker installation, you must run the Netmaker binary, CoreDNS binary, MongoDB, and a web server directly on the host. This requires all the requirements for those individual components. Our guided install assumes systemd-based linux, but there are many other ways to install Netmaker's individual components onto machines that do not support Docker. 
+    **Description:**  Allows specification of the string used to connect to grpc. Format: IP:PORT or DOMAIN:PORT. Defaults to SERVER_HOST if not specified.
 
-DNS Mode Prereqisite Setup
-====================================
+SERVER_HOST: *(depreciated, use SERVER_API_CONN_STRING and SERVER_GRPC_CONN_STRING)* 
+    **Default:** Server will perform an IP check and set automatically unless explicitly set, or DISABLE_REMOTE_IP_CHECK is set to true, in which case it defaults to 127.0.0.1
 
-If you plan on running the server in DNS Mode, know that a `CoreDNS Server <https://coredns.io/manual/toc/>`_ 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.
+    **Description:** Sets the SERVER_HTTP_HOST and SERVER_GRPC_HOST variables if they are unset. The address where traffic comes in. 
 
-However, on your host system (for Netmaker), this may conflict with an existing process. On linux systems running systemd-resolved, there is likely a service consuming port 53. The below steps will disable systemd-resolved, and replace it with a generic (e.g. Google) nameserver. Be warned that this may have consequences for any existing private DNS configuration. The following was tested on Ubuntu 20.04 and should be run prior to deploying the docker containers.
+SERVER_HTTP_HOST: *(depreciated, use SERVER_API_CONN_STRING and SERVER_GRPC_CONN_STRING)*
+    **Default:** Equals SERVER_HOST if set, "127.0.0.1" if SERVER_HOST is unset.
+    
+    **Description:** Set to make the HTTP and GRPC functions available via different interfaces/networks.
 
-1. ``systemctl stop systemd-resolved`` 
-2. ``systemctl disable systemd-resolved`` 
-3. ``vim /etc/systemd/resolved.conf``
-    * uncomment DNS and add 8.8.8.8 or whatever reachable nameserver is your preference
-    * uncomment DNSStubListener and set to "no"
-4. ``ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf``
+SERVER_GRPC_HOST: *(depreciated, use SERVER_API_CONN_STRING and SERVER_GRPC_CONN_STRING)*
+    **Default:** Equals SERVER_HOST if set, "127.0.0.1" if SERVER_HOST is unset.
 
-Port 53 should now be available for CoreDNS to use.
+    **Description:** Set to make the HTTP and GRPC functions available via different interfaces/networks.
 
-Docker Compose Install
-=======================
+API_PORT:
+    **Default:** 8081 
 
-The most simple (and recommended) way of installing Netmaker is to use one of the provided `Docker Compose files <https://github.com/gravitl/netmaker/tree/feature_v0.3.5_docs/compose>`_. Below are instructions for several different options to install Netmaker via Docker Compose, followed by an annotated reference Docker Compose in case your use case requires additional customization.
+    **Description:** The HTTP API port for Netmaker. Used for API calls / communication from front end.
 
-Slim Install - No DNS, No Client Mode, No Secure GRPC
---------------------------------------------------------
+GRPC_PORT:  
+    **Default:** 50051
 
-This is the same docker compose covered in the :doc:`quick start <./quick-start>`. It requires no special privileges and can run on any system with Docker and Docker Compose. However, it also does not have the full feature set, and lacks Client Mode and DNS Mode.
+    **Description:** The GRPC port for Netmaker. Used for communications from nodes.
 
-**Prerequisites:**
-  * ports 80, 8081, and 50051 are not blocked by firewall
-  * ports 80, 8081, 50051, and 27017 are not in use 
+MASTER_KEY:  
+    **Default:** "secretkey" 
 
-**Notes:** 
-  * You can still run the netclient on the host system even if Client Mode is not enabled. It will just be managed like the netclient on any other nodes, and will not be automatically managed by thhe server/UI.
-  * You can change the port mappings in the Docker Compose if the listed ports are already in use.
+    **Description:** The admin master key for accessing the API. Change this in any production installation.
 
-Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
+CORS_ALLOWED_ORIGIN:  
+    **Default:** "*"
 
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.slim.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+    **Description:** The "allowed origin" for API requests. Change to restrict where API requests can come from.
 
-Full Install - DNS, Client Mode, and Secure GRPC Enabled
-----------------------------------------------------------
+REST_BACKEND:  
+    **Default:** "on" 
 
-This installation gives you the fully-featured product with Client Mode and DNS Mode. 
+    **Description:** Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
 
-**Prerequisites:**
-  * systemd linux (Debian or Ubuntu reccommended)
-  * sudo privileges
-  * DNS Mode Prerequisite Setup (see above)
-  * WireGuard installed
-  * ports 80, 8081, 53, and 50555 are not blocked by firewall
-  * ports 80, 8081, 53, 50555, and 27017 are not in use
+AGENT_BACKEND:  
+    **Default:** "on" 
 
-**Notes:** 
-  * You can change the port mappings in the Docker Compose if the listed ports are already in use.
-  * You can run CoreDNS on a non-53 port, but this likely will cause issues on the client side (DNS on non-standard port). We do not recommend this and do not cover how to manage running CoreDNS on a different port for clients, which will likely have problems resolving a nameserver on a non-53 port.
+    **Description:** Enables the AGENT backend (GRPC running on GRPC_PORT at SERVER_GRPC_HOST). Change to "off" to turn off.
 
-Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
+DNS_MODE:  
+    **Default:** "off"
 
-#. ``sudo su -``
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+    **Description:** Enables DNS Mode, meaning config files will be generated for CoreDNS.
 
+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.
 
-Server Only Install - UI, DNS, Client Disabled
-------------------------------------------------
+.. literalinclude:: ../config/environments/dev.yaml
+  :language: YAML
 
-A "Server Only" install can be helpful for scenarios in which you do not want to run the UI. the UI is not mandatory for running a Netmaker network, but it makes the process easier. This mode also diables DNS and Client Modes, though you can add those back in if needed. There is no UI dependency on Client Mode or DNS Mode.
+Compose File - Annotated
+--------------------------------------
 
-**Prerequisites:**
-  * ports 8081 and 50051 are not blocked by firewall
-  * ports 8081, 50051, and 27017 are not in use
+All environment variables and options are enabled in this file. It is the equivalent to running the "full install" from the above section. However, all environment variables are included, and are set to the default values provided by Netmaker (if the environment variable was left unset, it would not change the installation). Comments are added to each option to show how you might use it to modify your installation.
 
-**Notes:**
-  * You can still run the netclient on the host system even if Client Mode is not enabled. It will just be managed like the netclient on any other nodes, and will not be automatically managed by thhe server/UI.
-  * You can change the port mappings in the Docker Compose if the listed ports are already in use.
+.. literalinclude:: ../compose/docker-compose.reference.yml
+  :language: YAML
 
-Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
 
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.server-only.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
+DNS Mode Setup
+====================================
 
-No DNS - CoreDNS Disabled, Client Enabled
-----------------------------------------------
+If you plan on running the server in DNS Mode, know that a `CoreDNS Server <https://coredns.io/manual/toc/>`_ 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.
 
-DNS Mode is currently limited to clients that can run resolvectl (systemd-resolved, see :doc:`Architecture docs <./architecture>` for more info). You may wish to disable DNS mode for various reasons. This installation option gives you the full feature set minus CoreDNS.
+However, on your host system (for Netmaker), this may conflict with an existing process. On linux systems running systemd-resolved, there is likely a service consuming port 53. The below steps will disable systemd-resolved, and replace it with a generic (e.g. Google) nameserver. Be warned that this may have consequences for any existing private DNS configuration. The following was tested on Ubuntu 20.04 and should be run prior to deploying the docker containers.
 
-**Prerequisites:**
-  * systemd linux (Debian or Ubuntu reccommended)
-  * sudo privileges
-  * WireGuard installed
-  * ports 80, 8081, and 50555 are not blocked by firewall
-  * ports 80, 8081, 50555, and 27017 are not in use
+.. code-block::
 
-**Notes:** 
-  * You can change the port mappings in the Docker Compose if the listed ports are already in use.
-  * If you would like to run DNS Mode, but disable it on some clients, this is also an option. See the :doc:`client installation <./client-installation>` documentation for more details.
+  systemctl stop systemd-resolved
+  systemctl disable systemd-resolved 
+  vim /etc/systemd/resolved.conf
+    *  uncomment DNS and add 8.8.8.8 or whatever reachable nameserver is your preference  *
+    *  uncomment DNSStubListener and set to "no"  *
+  ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
 
-Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
+Port 53 should now be available for CoreDNS to use.
 
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.nodns.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
 
-No DNS - CoreDNS Disabled, Client Enabled
+Docker Compose Install
+=======================
+
+The most simple (and recommended) way of installing Netmaker is to use one of the provided `Docker Compose files <https://github.com/gravitl/netmaker/tree/master/compose>`_. Below are instructions for several different options to install Netmaker via Docker Compose, followed by an annotated reference Docker Compose in case your use case requires additional customization.
 
-No Client - DNS Enabled, Client Disabled
----------------------------------------------
+Test Install - No DNS, No Secure GRPC
+--------------------------------------------------------
+
+This install will run Netmaker on a server without HTTPS using an IP address. This is not secure and not recommended, but can be helpful for testing.
 
-You may want to provide DNS, but do not want to run the server with special privileges, in which case you can run with just Client Mode disabled. It requires no special privileges and can run on any system with Docker and Docker Compose. 
+It also does not run the CoreDNS server, to simplify the deployment
 
 **Prerequisites:**
-  * ports 80, 8081, 53, and 50051 are not blocked by firewall
-  * ports 80, 8081, 53, 50051, and 27017 are not in use
-  * DNS Mode Prerequisite Setup (see above)
+  * server ports 80, 8081, and 50051 are not blocked by firewall
 
 **Notes:** 
-  * You can still run the netclient on the host system even if Client Mode is not enabled. It will just be managed like the netclient on any other nodes, and will not be automatically managed by thhe server/UI.
   * You can change the port mappings in the Docker Compose if the listed ports are already in use.
 
 Assuming you have Docker and Docker Compose installed, you can just run the following, replacing **< Insert your-host IP Address Here >** with your host IP (or domain):
 
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.noclient.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+.. code-block::
 
+  wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.test.yml
+  sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml
+  docker-compose up -d`
 
-Reference Compose File - Annotated
---------------------------------------
 
-All environment variables and options are enabled in this file. It is the equivalent to running the "full install" from the above section. However, all environment variables are included, and are set to the default values provided by Netmaker (if the environment variable was left unset, it would not change the installation). Comments are added to each option to show how you might use it to modify your installation.
+No DNS - CoreDNS Disabled
+----------------------------------------------
 
-.. literalinclude:: ../compose/docker-compose.reference.yml
-  :language: YAML
+DNS Mode is currently limited to clients that can run resolvectl (systemd-resolved, see :doc:`Architecture docs <./architecture>` for more info). You may wish to disable DNS mode for various reasons. This installation option gives you the full feature set minus CoreDNS.
+
+To run without DNS, follow the :doc:`Quick Install <./quick-start>` guide, omitting the steps for DNS setup. In addition, when the guide has you pull (wget) the Netmaker docker-compose template, use the following link instead:
+
+#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/docker-compose.nodns.yml``
+
+This template is equivalent but omits CoreDNS.
 
 
 Linux Install without Docker
@@ -178,35 +177,44 @@ Linux Install without Docker
 
 Most systems support Docker, but some, such as LXC, 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). 
 
-Below is a guided set of instructions for installing without Docker on Ubuntu 20.04. Depending on your system, the steps may vary.
+To start, we recommend following the Nginx instructions in the :doc:`Quick Install <./quick-start>` guide to enable SSL for your environment.
+
+Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.
 
-MongoDB Setup
+rqlite Setup
 ----------------
-1. Install MongoDB on your server:
-    * For Ubuntu: `sudo apt install -y mongodb`
-    * For more advanced installation or other operating systems, see  the `MongoDB documentation <https://docs.mongodb.com/manual/administration/install-community/>`_.
+1. Install rqlite on your server: https://github.com/rqlite/rqlite
 
-2. Create a user:
-    * ``mongo admin``  
-    * > `db.createUser({ user: "mongoadmin" , pwd: "mongopass", roles: ["userAdminAnyDatabase", "dbAdminAnyDatabase", "readWriteAnyDatabase"]})`
+2. Run rqlite: rqlited -node-id 1 ~/node.1
 
 Server Setup
 -------------
-1. **Run the install script:** ``sudo curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.3.5/scripts/netmaker-server.sh | sh -``
+1. **Run the install script:** 
+
+``sudo curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netmaker-server.sh | sh -``
+
 2. Check status:  ``sudo journalctl -u netmaker``
 3. If any settings are incorrect such as host or mongo credentials, change them under /etc/netmaker/config/environments/< your env >.yaml and then run ``sudo systemctl restart netmaker``
 
 UI Setup
 -----------
 
-The following uses NGinx as an http server. You may alternatively use Apache or any other web server that serves static web files.
+The following uses Nginx as an http server. You may alternatively use Apache or any other web server that serves static web files.
 
-1. **Download UI asset files:** ``sudo wget -O /usr/share/nginx/html/netmaker-ui.zip https://github.com/gravitl/netmaker-ui/releases/download/latest/netmaker-ui.zip``
-2. **Unzip:** ``sudo unzip /usr/share/nginx/html/netmaker-ui.zip -d /usr/share/nginx/html``
-3. **Copy Config to Nginx:** ``sudo cp /usr/share/nginx/html/nginx.conf /etc/nginx/conf.d/default.conf``
-4. **Modify Default Config Path:** ``sudo sed -i 's/root \/var\/www\/html/root \/usr\/share\/nginx\/html/g' /etc/nginx/sites-available/default``
-5. **Change Backend URL:** ``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'``
-6. **Start Nginx:** ``sudo systemctl start nginx``
+1. Download and Unzip UI asset files
+2. Copy Config to Nginx
+3. Modify Default Config Path
+4. Change Backend URL
+5. Start Nginx
+
+.. code-block::
+  
+  sudo wget -O /usr/share/nginx/html/netmaker-ui.zip https://github.com/gravitl/netmaker-ui/releases/download/latest/netmaker-ui.zip
+  sudo unzip /usr/share/nginx/html/netmaker-ui.zip -d /usr/share/nginx/html
+  sudo cp /usr/share/nginx/html/nginx.conf /etc/nginx/conf.d/default.conf
+  sudo sed -i 's/root \/var\/www\/html/root \/usr\/share\/nginx\/html/g' /etc/nginx/sites-available/default
+  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
 
 CoreDNS Setup
 ----------------
@@ -214,150 +222,103 @@ CoreDNS Setup
 Kubernetes Install
 =======================
 
-**This configuration is coming soon.** It will allow you to deploy Netmaker on a Kubernetes cluster.
-
-Configuration Reference
-=========================
+Server Install
+--------------------------
 
-The "Reference Compose File" (above) explains many of these options. However, it is important to understand fundamentally how Netmaker sets its configuration:
+This template assumes your cluster uses Nginx for ingress with valid wildcard certificates. If using an ingress controller other than Nginx (ex: Traefik), you will need to manually modify the Ingress entries in this template to match your environment.
 
-1. Defaults
-2. Config File
-3. Environment Variables
+This template also requires RWX storage. Please change references to storageClassName in this template to your cluster's Storage Class.
 
-Variable Description
-----------------------
+``wget https://raw.githubusercontent.com/gravitl/netmaker/develop/kube/netmaker-template.yaml``
 
-SERVER_HOST: 
-    **Default:** Server will perform an IP check and set automatically unless explicitly set, or DISABLE_REMOTE_IP_CHECK is set to true, in which case it defaults to 127.0.0.1
+Replace the NETMAKER_BASE_DOMAIN references to the base domain you would like for your Netmaker services (ui,api,grpc). Typically this will be something like **netmaker.yourwildcard.com**.
 
-    **Description:** Sets the SERVER_HTTP_HOST and SERVER_GRPC_HOST variables if they are unset. The address where traffic comes in. 
+``sed -i ‘s/NETMAKER_BASE_DOMAIN/<your base domain>/g’ netmaker-template.yaml``
 
-SERVER_HTTP_HOST: 
-    **Default:** Equals SERVER_HOST if set, "127.0.0.1" if SERVER_HOST is unset.
-    
-    **Description:** Set to make the HTTP and GRPC functions available via different interfaces/networks.
+Now, assuming Ingress and Storage match correctly with your cluster configuration, you can install Netmaker.
 
-SERVER_GRPC_HOST: 
-    **Default:** Equals SERVER_HOST if set, "127.0.0.1" if SERVER_HOST is unset.
+.. code-block::
 
-    **Description:** Set to make the HTTP and GRPC functions available via different interfaces/networks.
+  kubectl create ns nm
+  kubectl config set-context --current --namespace=nm
+  kubectl apply -f netmaker-template.yaml -n nm
 
-API_PORT:  
-    **Default:** 8081 
+In about 3 minutes, everything should be up and running:
 
-    **Description:** The HTTP API port for Netmaker. Used for API calls / communication from front end.
+``kubectl get ingress nm-ui-ingress-nginx``
 
-GRPC_PORT:  
-    **Default:** 50051
+Netclient Daemonset
+--------------------------
 
-    **Description:** The GRPC port for Netmaker. Used for communications from nodes.
+The following instructions assume you have Netmaker running and a network you would like to add your cluster into. The Netmaker server does not need to be running inside of a cluster for this.
 
-MASTER_KEY:  
-    **Default:** "secretkey" 
+.. code-block::
 
-    **Description:** The admin master key for accessing the API. Change this in any production installation.
+  wget https://raw.githubusercontent.com/gravitl/netmaker/develop/kube/netclient-template.yaml
+  sed -i ‘s/ACCESS_TOKEN_VALUE/< your access token value>/g’ netclient-template.yaml
+  kubectl apply -f netclient-template.yaml
 
-CORS_ALLOWED_ORIGIN:  
-    **Default:** "*"
+For a more detailed guide on integrating Netmaker with MicroK8s, `check out this guide <https://itnext.io/how-to-deploy-a-cross-cloud-kubernetes-cluster-with-built-in-disaster-recovery-bbce27fcc9d7>`_. 
 
-    **Description:** The "allowed origin" for API requests. Change to restrict where API requests can come from.
-
-REST_BACKEND:  
-    **Default:** "on" 
-
-    **Description:** Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
-
-AGENT_BACKEND:  
-    **Default:** "on" 
-
-    **Description:** Enables the AGENT backend (GRPC running on GRPC_PORT at SERVER_GRPC_HOST). Change to "off" to turn off.
-
-CLIENT_MODE:  
-    **Default:** "on" 
-
-    **Description:** Enables Client Mode, meaning netclient will be deployed on server and will be manageable from UI. Change to "off" to turn off.
-
-DNS_MODE:  
-    **Default:** "on"
-
-    **Description:** Enables DNS Mode, meaning config files will be generated for CoreDNS.
-
-DISABLE_REMOTE_IP_CHECK:  
-    **Default:** "off" 
-
-    **Description:** If turned "on", Server will not set Host based on remote IP check. This is already overridden if SERVER_HOST is set. Turned "off" by default.
-
-MONGO_ADMIN:  
-    **Default:** "mongoadmin" 
-
-    **Description:** Admin user for MongoDB.
-
-MONGO_PASS:  
-    **Default:** "mongopass" 
-
-    **Description:** Admin password for MongoDB.
-
-MONGO_HOST:  
-    **Default:** "127.0.0.1"
-
-    **Description:** Address of MongoDB.
-
-MONGO_PORT:  
-    **Default:** "27017"
-
-    **Description:** Port of MongoDB.
-
-MONGO_OPTS:  
-    **Default:** "/?authSource=admin"
-
-    **Description:** Opts to enable admin login for Mongo.
-
-SERVER_GRPC_WIREGUARD: 
-    **Default:** "on"
-
-    **Description:** Whether to run GRPC over a WireGuard network. On by default. Secures the server comms. Switch to "off" to turn off. If off and running in production, make sure to have certificates installed to secure GRPC communications. 
+Nginx Reverse Proxy Setup with https
+====================================
 
-SERVER_GRPC_WG_INTERFACE: 
-    **Default:** "nm-grpc-wg"
+The `Swag Proxy <https://github.com/linuxserver/docker-swag>`_ makes it easy to generate a valid ssl certificate for the config bellow. Here is the `documentation <https://docs.linuxserver.io/general/swag>`_ for the installation.
 
-    **Description:** Interface to use for GRPC WireGuard network if enabled
+The following file configures Netmaker as a subdomain. This config is an adaption from the swag proxy project.
 
-SERVER_GRPC_WG_ADDRESS:
-    **Default:** "10.101.0.1"
+./netmaker.subdomain.conf:
 
-    **Description:** Private Address to use for GRPC WireGuard network if enabled
+.. code-block:: nginx
 
-SERVER_GRPC_WG_ADDRESS_RANGE:
-    **Default:** "10.101.0.0/16"
+    server {
+        listen 443 ssl;
+        listen [::]:443 ssl;
 
-    **Description:** Private Address range to use for GRPC WireGard clients if enabled. Gives 65,534 total addresses for all of netmaker. If running a larger network, will need to configure addresses differently, for instance using ipv6, or use certificates instead.
+        server_name netmaker.*; # The external URL
+        client_max_body_size 0;
 
-SERVER_GRPC_WG_PORT:
-    **Default:** 50555
+        # A valid https certificate is needed.
+        include /config/nginx/ssl.conf;
 
-    **Description:** Port to use for GRPC WireGuard if enabled
+        location / {
+            # This config file can be found at:
+            # https://github.com/linuxserver/docker-swag/blob/master/root/defaults/proxy.conf
+            include /config/nginx/proxy.conf;
 
-SERVER_GRPC_WG_PUBKEY:
-    **Default:** < generated at startup >
+            # if you use a custom resolver to find your app, needed with swag proxy
+            # resolver 127.0.0.11 valid=30s;
+            set $upstream_app netmaker-ui;                             # The internal URL
+            set $upstream_port 80;                                     # The internal Port
+            set $upstream_proto http;                                  # the protocol that is being used
+            proxy_pass $upstream_proto://$upstream_app:$upstream_port; # combine the set variables from above
+            }
+        }
 
-    **Description:** PublicKey for GRPC WireGuard interface. Generated if left blank.
+    server {
+        listen 443 ssl;
+        listen [::]:443 ssl;
 
-SERVER_GRPC_WG_PRIVKEY:
-    **Default:** < generated at startup >
+        server_name backend-netmaker.*; # The external URL
+        client_max_body_size 0;
+        underscores_in_headers on;
 
-    **Description:** PrivateKey for GRPC WireGuard interface. Generated if left blank.
+        # A valid https certificate is needed.
+        include /config/nginx/ssl.conf;
 
-SERVER_GRPC_WG_KEYREQUIRED
-    **Default:** ""
+        location / {
+            # if you use a custom resolver to find your app, needed with swag proxy
+            # resolver 127.0.0.11 valid=30s;
 
-    **Description:** Determines if an Access Key is required to join the Comms network. Blank (meaning 'no') by default. Set to "yes" to turn on.
+            set $upstream_app netmaker;                                # The internal URL
+            set $upstream_port 8081;                                   # The internal Port
+            set $upstream_proto http;                                  # the protocol that is being used
+            proxy_pass $upstream_proto://$upstream_app:$upstream_port; # combine the set variables from above
 
+            # Forces the header to be the one that is visible from the outside
+            proxy_set_header                Host backend.netmaker.example.org; # Please cange to your URL
 
-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 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
-  :language: YAML
-
+            # Pass all headers through to the backend
+            proxy_pass_request_headers      on;
+            }
+        }

+ 6 - 20
docs/support.rst

@@ -10,22 +10,15 @@ Does/Will Netmaker Support X Operating System?
 
 Netmaker is initially available on a limited number of operating systems for good reason: Every operating system is designed differently. With a small team, we can either focus on making Netmaker do a lot on a few number of operating systems, or a little on a bunch of operating systems. We chose the first option. You can view the System Compatibility docs for more info, but in general, you should only be using Netmaker on systemd linux right now.
 
-However, as of v0.4, we will technically be able to bring any operating system into the network. This is a bit of a hack. v0.4 introduces Ingress Gateways. Think of it this way. You set up a private network. You want devices to access it. You set up a single node as an "Ingress Gateway" and generate config files for "external clients." These clients are unmanaged and unmeshed, meaning they can access the network but only via the gateway. It also means they will not automatically account for changes to the network, and the user will have to update the configs manually.
+However, via "external clients", any device that supports WireGuard can be added to the network. 
 
-This lets us immediately "support" any device which can run WireGuard, which includes most operating systems at this point including phones and Windows.
-
-As we stabilize the design and feature set of Netmaker, we will expand the operating system support for Netclient which configures dynamic, fully-meshed devices. Expect to see updates about new OS support every few weeks, until eventually the Ingress Gateway becomes unnecessary (though you will still want it for certain use cases).
+In future iterations will expand the operating system support for Netclient, and devices that must use the "external client" feature can switch to Netclient.
 
 How do I install the Netclient on X?
 ---------------------------------------
 
 As per the above, there are many unsupported operating systems. You are still welcome to try, it is just an executable binary file after all. If the system is unix-based and has kernel WireGuard installed, netclient may very well mesh the device into the network. However, the service likely will encounter problems retrieving updates.
 
-Why MongoDB? SQL is better and smaller.
-----------------------------------------
-
-We are in a phase of rapid iteration. Every week the database schema changes. MongoDB makes our development process much more flexible. That said, we agree! SQL will be better for production, and indeed, we plan to switch over to SQL before v1.0, so please be patient with the resource consumption of MongoDB for the time being; it is helping to support a rapid pace of development. 
-
 
 Is Netmaker a VPN like NordNPN?
 --------------------------------
@@ -41,10 +34,11 @@ https://github.com/pivpn/pivpn
 https://github.com/subspacecloud/subspace
 https://github.com/mullvad/mullvadvpn-app
 
-Do you offer any paid support?
----------------------------------
+Do you offer any enterprise support?
+--------------------------------------
+
+If you are interested in enterprise support for your project, please contact [email protected].
 
-Not at this time, but eventually we will. If you are interested, or if you are interested in sponsoring the project generally, please contact Alex Feiszli ([email protected]).
 
 Why the SSPL License?
 ----------------------
@@ -57,14 +51,6 @@ If you have concerns about the license leading to project restrictions down the
 
 All that said, we will re-evaluate the license on a regular basis and determine if an OSI-approved license makes more sense. It's just easier to move from SSPL to another license than vice-versa.
 
-Issues, Bugs, and Feature Requests
-=====================================
-
-Issues / Bugs
-----------------
-
-Feature Requests
--------------------
 
 Contact
 ===========

+ 75 - 1
docs/troubleshoot.rst

@@ -3,17 +3,91 @@ Troubleshooting
 =================
 
 Common Issues
----------------
+--------------
+**How can I connect my Android, IOS, MacOS or Windows device to my Netmaker VPN?**
+  Currently meshing one of these devices is not supported, however it will be soon. 
+  For now you can connect to your VPN by making one of the nodes an Ingressgateway, then 
+  create an Ext Client for each device. Finally, use the official WG app or another 
+  WG configuration app to connect via QR or downloading the device's WireGuard configuration. 
+
+**I've made changes to my nodes but the nodes themselves haven't updated yet, why?**
+  Please allow your nodes to complete a check in or two, in order to reconfigure themselves.
+  In some cases, it could take up to a minute or so.
+
+**Do I have to use access keys to join a network?**
+  Although keys are the preferred way to join a network, Netmaker does allow for manual node sign-ups.
+  Simply turn on "allow manual signups" on your network and nodes will not connect until you manually aprove each one.
+
+**Is there a community or forum to ask questions about Netmaker?**
+  Yes, we have an active `discord <https://discord.gg/Pt4T9y9XK8>`_ community and issues on our `github <https://github.com/gravitl/netmaker/issues>`_ are answered frequently!
+  You can also sign-up for updates at our `gravitl site <https://gravitl.com/>`_!
 
 Server
 -------
+**Can I secure/encrypt all the traffic to my server and UI?**
+  This can fairly simple to achieve assuming you have access to a domain and are familiar with Nginx.
+  Please refer to the quick-start guide to see!
+
+**Can I connect multiple nodes (mesh clients) behind a single firewall/router?**
+  Yes! As of version 0.7 Netmaker supports UDP Hole Punching to allow this, without the use of a third party STUN server!
+  Is UDP hole punching a risk for you? Well you can turn it off and make static nodes/ports for the server to refer to as well.
+
+**What are the minimum specs to run the server?**
+  We recommend at least 1 CPU and 2 GB Memory.
+
+**Does this support IPv6 addressing?**
+  Yes, Netmaker supports IPv6 addressing. When you create a network, just make sure to turn on Dual Stack.
+  Nodes will be given IPv6 addresses along with their IPv4 address. It does not currently support IPv6 only.
+
+**Does Netmaker support Raft Consensus?**
+  Netmaker does not directly support it, but it uses `rqlite <https://github.com/rqlite/rqlite>`_ (which supports Raft) as the database.
+
+**How do I uninstall Netmaker?**
+  There is no official uninstall script for the Netmaker server at this time. If you followed the quick-start guide, simply run ``sudo docker-compose -f docker-compose.quickstart.yml down --volumes``
+  to completely wipe your server. Otherwise kill the running binary and it's up to you to remove database records/volumes.
 
 UI
 ----
+**I want to make a seperate network and give my friend access to only that network.**
+  Simply navigate to the UI (as an admin account). Select users in the top left and create them an account.
+  Select the network(s) to give them and they should be good to go! They are an admin of that network(s) only now.
+
+**I'm done with an access key, can I delete it?**
+  Simply navigate to the UI (as an admin account). Select your network of interest, then the select the ``Access Keys`` tab.
+  Then delete the rogue access key.
+
+**I can't delete my network, why?**
+  You **MUST** remove all nodes in a network before you can delete it.
+
+**Can I have multiple nodes with the same name?**
+  Yes, nodes can share names without issue. It may just be harder on you to know which is which.
 
 Agent
 -------
+**How do I connect a node to my Netmaker network with Netclient?**
+  First get your access token (not just access key), then run ``sudo netclient join -t <access token>``.
+  **NOTE:** netclient may be under /etc/netclient/, i.e run ``sudo /etc/netclient/netclient join -t <access token>``
+
+**How do I disconnect a node on a Netmaker network?**
+  In order to leave a Netmaker network, run ``sudo netclient leave -n <network-name>``
+
+**How do I check the logs of my agent on a node?**
+  You will need sudo/root permissions, but you can run ``sudo systemctl status netclient@<insert network name>``
+  or you may also run ``sudo journalctl -u netclient@<network name>``. 
+  Note for journalctl: you should hit the ``end`` key to get to view the most recent logs quickly or use ``journalctl -u netclient@<network name> -f`` instead.
+
+**Can I check the configuration of my node on the node?**
+  **A:** Yes, on the node simply run ``sudo cat /etc/netclient/netconfig-<network name>`` and you should see what your current configuration is! 
+  You can also see the current WireGuard configuration with ``sudo wg show``
+
+**I am done with the agent on my machine, can I uninstall it?**
+  Yes, on the node simply run ``sudo /etc/netclient/netclient uninstall``. 
+
 
 CoreDNS
 --------
+**Is CoreDNS required to use Netmaker?**
+  CoreDNS is not required. Simply start your server with ``DNS_MODE="off"``.
 
+**What is the minimum DNS entry value I can use?**
+  Netmaker supports down to two characters for DNS names for your networks domains**

+ 3 - 18
docs/usage.rst

@@ -19,21 +19,6 @@ Video Tutorials
 
 Written Tutorials
 -----------------
-* `Kubernetes Cross-cloud cluster <https://itnext.io/how-to-deploy-a-single-kubernetes-cluster-across-multiple-clouds-using-k3s-and-wireguard-a5ae176a6e81>`_: Tutorial on setting up cross-cloud Kubernetes clusters using Netmaker.
-
-Basic
-=====
-
-Local Network
-=============
-  
-Site-to-Site
-============
-
-Dual Stack with IPv6
-====================
-
-Kubernetes Node Network
-========================
-
-
+* `K3s Cross-cloud cluster <https://itnext.io/how-to-deploy-a-single-kubernetes-cluster-across-multiple-clouds-using-k3s-and-wireguard-a5ae176a6e81>`_: Tutorial on setting up cross-cloud K3s clusters using Netmaker.
+* `MicroK8s Cross-cloud cluster <https://itnext.io/how-to-deploy-a-cross-cloud-kubernetes-cluster-with-built-in-disaster-recovery-bbce27fcc9d7>`_: Tutorial on setting up cross-cloud MicroK8s clusters using Netmaker.
+* `Secure access to private services <https://afeiszli.medium.com/how-to-enable-secure-access-to-your-hosted-services-using-netmaker-and-wireguard-1b3282d4b7aa>`_: Tutorial on setting up secure Nextcloud with Netmaker.

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