Browse Source

Merge pull request #366 from gravitl/feature_v0.8.4_fixtests

Feature v0.8.4 fixtests
Alex 3 years ago
parent
commit
9595d3da79
55 changed files with 2126 additions and 482 deletions
  1. 4 10
      .github/workflows/test.yml
  2. 3 4
      README.md
  3. 1 0
      config/config.go
  4. 51 1
      database/database.go
  5. 7 6
      database/postgres.go
  6. 11 1
      docker/Dockerfile-userspace
  7. 0 23
      docker/Dockerfile-wg-quick
  8. BIN
      docs/_build/doctrees/architecture.doctree
  9. BIN
      docs/_build/doctrees/environment.pickle
  10. BIN
      docs/_build/doctrees/server-installation.doctree
  11. 1 1
      docs/_build/html/.buildinfo
  12. 5 5
      docs/_build/html/_sources/architecture.rst.txt
  13. 162 10
      docs/_build/html/_sources/server-installation.rst.txt
  14. 1 1
      docs/_build/html/_static/documentation_options.js
  15. 26 5
      docs/_build/html/about.html
  16. 26 5
      docs/_build/html/api.html
  17. 35 14
      docs/_build/html/architecture.html
  18. 26 5
      docs/_build/html/client-installation.html
  19. 26 5
      docs/_build/html/conduct.html
  20. 13 6
      docs/_build/html/external-clients.html
  21. 13 6
      docs/_build/html/genindex.html
  22. 26 5
      docs/_build/html/getting-started.html
  23. 15 7
      docs/_build/html/index.html
  24. 13 6
      docs/_build/html/install.html
  25. 26 5
      docs/_build/html/license.html
  26. BIN
      docs/_build/html/objects.inv
  27. 26 5
      docs/_build/html/quick-start-nginx.html
  28. 29 8
      docs/_build/html/quick-start.html
  29. 13 6
      docs/_build/html/search.html
  30. 0 0
      docs/_build/html/searchindex.js
  31. 190 14
      docs/_build/html/server-installation.html
  32. 26 5
      docs/_build/html/support.html
  33. 26 5
      docs/_build/html/troubleshoot.html
  34. 26 5
      docs/_build/html/usage.html
  35. 5 5
      docs/architecture.rst
  36. 1 1
      docs/conf.py
  37. 162 10
      docs/server-installation.rst
  38. 110 0
      logic/network.go
  39. 473 0
      logic/server.go
  40. 47 0
      logic/serverconf.go
  41. 33 4
      logic/util.go
  42. 289 0
      logic/wireguard.go
  43. 2 1
      main.go
  44. 6 3
      netclient/command/commands.go
  45. 10 29
      netclient/daemon/systemd.go
  46. 39 50
      netclient/functions/checkin.go
  47. 1 1
      netclient/functions/common.go
  48. 36 51
      netclient/functions/join.go
  49. 6 1
      netclient/main.go
  50. 7 2
      netclient/ncutils/netclientutils.go
  51. 27 90
      netclient/server/grpc.go
  52. 2 1
      netclient/wireguard/unix.go
  53. 6 0
      scripts/userspace-entrypoint.sh
  54. 16 3
      servercfg/serverconf.go
  55. 21 51
      serverctl/serverctl.go

+ 4 - 10
.github/workflows/test.yml

@@ -6,14 +6,8 @@ on:
 jobs:
   tests:
     env:
-      DATABASE: rqlite
-    runs-on: ubuntu-latest
-    services:
-      rqlite:
-        image: rqlite/rqlite
-        ports:
-            - 4001:4001
-            - 4002:4002
+      DATABASE: sqlite
+    runs-on: ubuntu-20.04
     steps:
       - name: Checkout
         uses: actions/checkout@v2
@@ -21,5 +15,5 @@ jobs:
         run: |
             go test -p 1 ./... -v
         env:
-          DATABASE: rqlite
-          CLIENT_MODE: "off"
+          DATABASE: sqlite
+          CLIENT_MODE: "off"

+ 3 - 4
README.md

@@ -8,13 +8,13 @@
 
 <p align="center">
   <a href="https://github.com/gravitl/netmaker/releases">
-    <img src="https://img.shields.io/docker/v/gravitl/netmaker?color=blue" />
+    <img src="https://img.shields.io/badge/Version-0.8.4-informational?style=flat-square" />
   </a>
   <a href="https://discord.gg/zRb9Vfhk8A">
-    <img src="https://img.shields.io/badge/community-discord-purple" />
+    <img src="https://img.shields.io/badge/community-discord-informational" />
   </a>
   <a href="https://github.com/gravitl/netmaker/graphs/contributors">
-    <img src="https://img.shields.io/github/commit-activity/w/gravitl/netmaker?color=brightgreen" />
+    <img src="https://img.shields.io/github/commit-activity/w/gravitl/netmaker?color=blue" />
   </a>
   <a href="https://gravitl.com/resources">
     <img src="https://img.shields.io/badge/learning-resources-9cf" />
@@ -27,7 +27,6 @@
   </a>
 </p>
 
-
 # WireGuard® Automation from Homelab to Enterprise
 - [x] Peer-to-Peer Mesh Networks
 - [x] Site-to-Site Gateways

+ 1 - 0
config/config.go

@@ -61,6 +61,7 @@ type ServerConfig struct {
 	CheckinInterval      string `yaml:checkininterval`
 	DefaultNodeLimit     int32  `yaml:"defaultnodelimit"`
 	Verbosity            int32  `yaml:"verbosity"`
+	ServerCheckinInterval int64  `yaml:"servercheckininterval"`
 }
 
 

+ 51 - 1
database/database.go

@@ -3,33 +3,74 @@ package database
 import (
 	"encoding/json"
 	"errors"
-	"github.com/gravitl/netmaker/servercfg"
 	"log"
 	"time"
+
+	"github.com/gravitl/netmaker/servercfg"
 )
 
+// NETWORKS_TABLE_NAME - networks table
 const NETWORKS_TABLE_NAME = "networks"
+
+// NODES_TABLE_NAME - nodes table
 const NODES_TABLE_NAME = "nodes"
+
+// DELETED_NODES_TABLE_NAME - deleted nodes table
 const DELETED_NODES_TABLE_NAME = "deletednodes"
+
+// USERS_TABLE_NAME - users table
 const USERS_TABLE_NAME = "users"
+
+// DNS_TABLE_NAME - dns table
 const DNS_TABLE_NAME = "dns"
+
+// EXT_CLIENT_TABLE_NAME - ext client table
 const EXT_CLIENT_TABLE_NAME = "extclients"
+
+// INT_CLIENTS_TABLE_NAME - int client table
 const INT_CLIENTS_TABLE_NAME = "intclients"
+
+// PEERS_TABLE_NAME - peers table
 const PEERS_TABLE_NAME = "peers"
+
+// SERVERCONF_TABLE_NAME
+const SERVERCONF_TABLE_NAME = "serverconf"
+
+// DATABASE_FILENAME - database file name
 const DATABASE_FILENAME = "netmaker.db"
 
 // == ERROR CONSTS ==
+
+// NO_RECORD - no singular result found
 const NO_RECORD = "no result found"
+
+// NO_RECORDS - no results found
 const NO_RECORDS = "could not find any records"
 
 // == Constants ==
+
+// INIT_DB - initialize db
 const INIT_DB = "init"
+
+// CREATE_TABLE - create table const
 const CREATE_TABLE = "createtable"
+
+// INSERT - insert into db const
 const INSERT = "insert"
+
+// INSERT_PEER - insert peer into db const
 const INSERT_PEER = "insertpeer"
+
+// DELETE - delete db record const
 const DELETE = "delete"
+
+// DELETE_ALL - delete a table const
 const DELETE_ALL = "deleteall"
+
+// FETCH_ALL - fetch table contents const
 const FETCH_ALL = "fetchall"
+
+// CLOSE_DB - graceful close of db const
 const CLOSE_DB = "closedb"
 
 func getCurrentDB() map[string]interface{} {
@@ -72,17 +113,20 @@ func createTables() {
 	createTable(EXT_CLIENT_TABLE_NAME)
 	createTable(INT_CLIENTS_TABLE_NAME)
 	createTable(PEERS_TABLE_NAME)
+	createTable(SERVERCONF_TABLE_NAME)
 }
 
 func createTable(tableName string) error {
 	return getCurrentDB()[CREATE_TABLE].(func(string) error)(tableName)
 }
 
+// IsJSONString - checks if valid json
 func IsJSONString(value string) bool {
 	var jsonInt interface{}
 	return json.Unmarshal([]byte(value), &jsonInt) == nil
 }
 
+// Insert - inserts object into db
 func Insert(key string, value string, tableName string) error {
 	if key != "" && value != "" && IsJSONString(value) {
 		return getCurrentDB()[INSERT].(func(string, string, string) error)(key, value, tableName)
@@ -91,6 +135,7 @@ func Insert(key string, value string, tableName string) error {
 	}
 }
 
+// InsertPeer - inserts peer into db
 func InsertPeer(key string, value string) error {
 	if key != "" && value != "" && IsJSONString(value) {
 		return getCurrentDB()[INSERT_PEER].(func(string, string) error)(key, value)
@@ -99,10 +144,12 @@ func InsertPeer(key string, value string) error {
 	}
 }
 
+// DeleteRecord - deletes a record from db
 func DeleteRecord(tableName string, key string) error {
 	return getCurrentDB()[DELETE].(func(string, string) error)(tableName, key)
 }
 
+// DeleteAllRecords - removes a table and remakes
 func DeleteAllRecords(tableName string) error {
 	err := getCurrentDB()[DELETE_ALL].(func(string) error)(tableName)
 	if err != nil {
@@ -115,6 +162,7 @@ func DeleteAllRecords(tableName string) error {
 	return nil
 }
 
+// FetchRecord - fetches a record
 func FetchRecord(tableName string, key string) (string, error) {
 	results, err := FetchRecords(tableName)
 	if err != nil {
@@ -126,10 +174,12 @@ func FetchRecord(tableName string, key string) (string, error) {
 	return results[key], nil
 }
 
+// FetchRecords - fetches all records in given table
 func FetchRecords(tableName string) (map[string]string, error) {
 	return getCurrentDB()[FETCH_ALL].(func(string) (map[string]string, error))(tableName)
 }
 
+// CloseDB - closes a database gracefully
 func CloseDB() {
 	getCurrentDB()[CLOSE_DB].(func())()
 }

+ 7 - 6
database/postgres.go

@@ -1,15 +1,17 @@
 package database
 
 import (
-	"github.com/gravitl/netmaker/servercfg"
 	"database/sql"
 	"errors"
-	_ "github.com/lib/pq"
 	"fmt"
+	"github.com/gravitl/netmaker/servercfg"
+	_ "github.com/lib/pq"
 )
 
+// PGDB - database object for PostGreSQL
 var PGDB *sql.DB
 
+// PG_FUNCTIONS - map of db functions for PostGreSQL
 var PG_FUNCTIONS = map[string]interface{}{
 	INIT_DB:      initPGDB,
 	CREATE_TABLE: pgCreateTable,
@@ -21,14 +23,13 @@ var PG_FUNCTIONS = map[string]interface{}{
 	CLOSE_DB:     pgCloseDB,
 }
 
-func getPGConnString() string{
+func getPGConnString() string {
 	pgconf := servercfg.GetSQLConf()
 	pgConn := fmt.Sprintf("host=%s port=%d user=%s "+
-	  "password=%s dbname=%s sslmode=%s",
-	  pgconf.Host, pgconf.Port, pgconf.Username, pgconf.Password, pgconf.DB, pgconf.SSLMode)
+		"password=%s dbname=%s sslmode=%s connect_timeout=5",
+		pgconf.Host, pgconf.Port, pgconf.Username, pgconf.Password, pgconf.DB, pgconf.SSLMode)
 	return pgConn
 }
-  
 
 func initPGDB() error {
 	connString := getPGConnString()

+ 11 - 1
docker/Dockerfile-userspace

@@ -10,7 +10,17 @@ RUN git clone https://git.zx2c4.com/wireguard-go && \
     make && \
     make install
 
+ENV WITH_WGQUICK=yes
+RUN git clone https://git.zx2c4.com/wireguard-tools && \
+    cd wireguard-tools && \
+    cd src && \
+    make && \
+    make install
+
 FROM gravitl/netmaker:${NM_VERSION}
 
-RUN apk add --no-cache --update libmnl iptables openresolv iproute2
+RUN apk add --no-cache --update bash libmnl iptables openresolv iproute2
 COPY --from=builder /usr/bin/wireguard-go /usr/bin/wg* /usr/bin/
+COPY scripts/userspace-entrypoint.sh ./entrypoint.sh
+
+ENTRYPOINT ["/bin/sh", "./entrypoint.sh"]

+ 0 - 23
docker/Dockerfile-wg-quick

@@ -1,23 +0,0 @@
-ARG NM_VERSION=
-
-FROM gravitl/builder as builder
-
-RUN apk add --update git build-base libmnl-dev iptables
-
-WORKDIR /root/
-RUN git clone https://git.zx2c4.com/wireguard-go && \
-    cd wireguard-go && \
-    make && \
-    make install
-
-ENV WITH_WGQUICK=yes
-RUN git clone https://git.zx2c4.com/wireguard-tools && \
-    cd wireguard-tools && \
-    cd src && \
-    make && \
-    make install
-
-FROM gravitl/netmaker:${NM_VERSION}
-
-RUN apk add --no-cache --update bash libmnl iptables openresolv iproute2
-COPY --from=builder /usr/bin/wireguard-go /usr/bin/wg* /usr/bin/

BIN
docs/_build/doctrees/architecture.doctree


BIN
docs/_build/doctrees/environment.pickle


BIN
docs/_build/doctrees/server-installation.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: c5f7c337a81aafa96c2a1d23d89efa34
+config: c42328d03e8a69bc128d18c18d0c8114
 tags: 645f666f9bcd5a90fca523b33c5a78b7

+ 5 - 5
docs/_build/html/_sources/architecture.rst.txt

@@ -77,13 +77,13 @@ Netmaker Server
 
 The Netmaker server is, at its core, a golang binary. Source code can be found `on GitHub <https://github.com/gravitl/netmaker>`_. The binary, by itself can be compiled for most systems. If you need to run the Netmaker server on a particular system, it likely can be made to work. In typical deployments, it is run as a Docker container. It can also be run as a systemd service as outlined in the non-docker install guide.
 
-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).
+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, 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).
 
 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.
 
 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 either sqlit (default) or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.
+The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.
 
 
 Netclient
@@ -104,10 +104,10 @@ If running in daemon mode, on a periodic basis (systemd timer), the netclient pe
 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.
 
 
-sqlite and rqlite
----------------------
+Datavase (sqlite, rqlite, postgres)
+-------------------------------------
 
-As of v0.8, Netmaker uses sqlite by default as a database. It can also use rqlite, a distributed (RAFT consensus) databaseand. Netmaker interacts with this database to store and retrieve information about nodes, networks, and users. 
+As of v0.8, Netmaker uses sqlite by default as a database. It can also use PostgreSQL, or rqlite, a distributed (RAFT consensus) databaseand. Netmaker interacts with this database to store and retrieve information about nodes, networks, and users. 
 
 Additional database support (besides sqlite and rqlite) is very easy to implement for special use cases. 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.
 

+ 162 - 10
docs/_build/html/_sources/server-installation.rst.txt

@@ -9,7 +9,7 @@ System Compatibility
 
 Netmaker will require elevated privileges to perform network operations. Netmaker has similar limitations to :doc:`netclient <./client-installation>` (client networking agent). 
 
-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.
+Typically, Netmaker is run inside of containers (Docker). To run a non-docker installation, you must run the Netmaker binary, CoreDNS binary, database, and a web server directly on the host. Each of these components have their own individual requirements.
 
 The quick install guide is recommended for first-time installs. 
 
@@ -101,13 +101,38 @@ DNS_MODE:
 DATABASE:  
     **Default:** "sqlite"
 
-    **Description:** Specify db type to connect with. Currently, options include "sqlite" and "rqlite".
+    **Description:** Specify db type to connect with. Currently, options include "sqlite", "rqlite", and "postgres".
 
-SQL_CONN:  
+SQL_CONN:
     **Default:** "http://"
 
     **Description:** Specify the necessary string to connect with your local or remote sql database.
 
+SQL_HOST:
+    **Default:** "localhost"
+
+    **Description:** Host where postgres is running.
+
+SQL_PORT:
+    **Default:** "5432"
+
+    **Description:** port postgres is running.
+
+SQL_DB:
+    **Default:** "netmaker"
+
+    **Description:** DB to use in postgres.
+
+SQL_USER:
+    **Default:** "postgres"
+
+    **Description:** User for posgres.
+
+SQL_PASS:
+    **Default:** "nopass"
+
+    **Description:** Password for postgres.
+
 CLIENT_MODE:  
     **Default:** "on"
 
@@ -344,18 +369,135 @@ The following file configures Netmaker as a subdomain. This config is an adaptio
 
 .. _HAInstall:
 
-Highly Available Installation
-===============================
+
+
+Highly Available Installation (Kubernetes)
+==================================================
+
+Netmaker comes with a Helm chart to deploy with High Availability on Kubernetes:
+
+.. code-block::
+
+    helm repo add netmaker https://gravitl.github.io/netmaker-helm/
+    helm repo update
+
+Requirements
+---------------
+
+To run HA Netmaker on Kubernetes, your cluster must have the following:
+- RWO and RWX Storage Classes (RWX is only required if running Netmaker with DNS Management enabled).
+- An Ingress Controller and valid TLS certificates 
+- This chart can currently generate ingress for Nginx or Traefik Ingress with LetsEncrypt + Cert Manager
+- If LetsEncrypt and CertManager are not deployed, you must manually configure certificates for your ingress
+
+Furthermore, the chart will by default install and use a postgresql cluster as its datastore.
+
+Recommended Settings:
+----------------------
+A minimal HA install of Netmaker can be run with the following command:
+`helm install netmaker --generate-name --set baseDomain=nm.example.com`
+This install has some notable exceptions:
+- Ingress **must** be manually configured post-install (need to create valid Ingress with TLS)
+- Server will use "userspace" WireGuard, which is slower than kernel WG
+- DNS will be disabled
+
+Example Installations:
+------------------------
+An annotated install command:
+
+.. code-block::
+
+    helm install netmaker/netmaker --generate-name \ # generate a random id for the deploy 
+    --set baseDomain=nm.example.com \ # the base wildcard domain to use for the netmaker api/dashboard/grpc ingress 
+    --set replicas=3 \ # number of server replicas to deploy (3 by default) 
+    --set ingress.enabled=true \ # deploy ingress automatically (requires nginx or traefik and cert-manager + letsencrypt) 
+    --set ingress.className=nginx \ # ingress class to use 
+    --set ingress.tls.issuerName=letsencrypt-prod \ # LetsEncrypt certificate issuer to use 
+    --set dns.enabled=true \ # deploy and enable private DNS management with CoreDNS 
+    --set dns.clusterIP=10.245.75.75 --set dns.RWX.storageClassName=nfs \ # required fields for DNS 
+    --set postgresql-ha.postgresql.replicaCount=2 \ # number of DB replicas to deploy (default 2)
+
+
+The below command will install netmaker with two server replicas, a coredns server, and ingress with routes of api.nm.example.com, grpc.nm.example.com, and dashboard.nm.example.com. CoreDNS will be reachable at 10.245.75.75, and will use NFS to share a volume with Netmaker (to configure dns entries).
+
+.. code-block::
+
+    helm install netmaker/netmaker --generate-name --set baseDomain=nm.example.com \
+    --set replicas=2 --set ingress.enabled=true --set dns.enabled=true \
+    --set dns.clusterIP=10.245.75.75 --set dns.RWX.storageClassName=nfs \
+    --set ingress.className=nginx
+
+The below command will install netmaker with three server replicas (the default), **no coredns**, and ingress with routes of api.netmaker.example.com, grpc.netmaker.example.com, and dashboard.netmaker.example.com. There will be one UI replica instead of two, and one database instance instead of two. Traefik will look for a ClusterIssuer named "le-prod-2" to get valid certificates for the ingress. 
+
+.. code-block::
+
+    helm3 install netmaker/netmaker --generate-name \
+    --set baseDomain=netmaker.example.com --set postgresql-ha.postgresql.replicaCount=1 \
+    --set ui.replicas=1 --set ingress.enabled=true \
+    --set ingress.tls.issuerName=le-prod-2 --set ingress.className=traefik
+
+Below, we discuss the considerations for Ingress, Kernel WireGuard, and DNS.
+
+Ingress	
+----------
+To run HA Netmaker, you must have ingress installed and enabled on your cluster with valid TLS certificates (not self-signed). If you are running Nginx as your Ingress Controller and LetsEncrypt for TLS certificate management, you can run the helm install with the following settings:
+
+- `--set ingress.enabled=true`
+- `--set ingress.annotations.cert-manager.io/cluster-issuer=<your LE issuer name>`
+
+If you are not using Nginx or Traefik and LetsEncrypt, we recommend leaving ingress.enabled=false (default), and then manually creating the ingress objects post-install. You will need three ingress objects with TLS:
+
+- `dashboard.<baseDomain>`
+- `api.<baseDomain>`
+- `grpc.<baseDomain>`
+
+If deploying manually, the gRPC ingress object requires special considerations. Look up the proper way to route grpc with your ingress controller. For instance, on Traefik, an IngressRouteTCP object is required.
+
+There are some example ingress objects in the kube/example folder.
+
+Kernel WireGuard
+------------------
+If you have control of the Kubernetes worker node servers, we recommend **first** installing WireGuard on the hosts, and then installing HA Netmaker in Kernel mode. By default, Netmaker will install with userspace WireGuard (wireguard-go) for maximum compatibility, and to avoid needing permissions at the host level. If you have installed WireGuard on your hosts, you should install Netmaker's helm chart with the following option:
+
+- `--set wireguard.kernel=true`
+
+DNS
+----------
+By Default, the helm chart will deploy without DNS enabled. To enable DNS, specify with:
+
+- `--set dns.enabled=true` 
+
+This will require specifying a RWX storage class, e.g.:
+
+- `--set dns.RWX.storageClassName=nfs`
+
+This will also require specifying a service address for DNS. Choose a valid ipv4 address from the service IP CIDR for your cluster, e.g.:
+
+- `--set dns.clusterIP=10.245.69.69`
+
+**This address will only be reachable from hosts that have access to the cluster service CIDR.** It is only designed for use cases related to k8s. If you want a more general-use Netmaker server on Kubernetes for use cases outside of k8s, you will need to do one of the following:
+- bind the CoreDNS service to port 53 on one of your worker nodes and set the COREDNS_ADDRESS equal to the public IP of the worker node
+- Create a private Network with Netmaker and set the COREDNS_ADDRESS equal to the private address of the host running CoreDNS. For this, CoreDNS will need a node selector and will ideally run on the same host as one of the Netmaker server instances.
+
+Values
+---------
+
+To view all options for the chart, please visit the README in the code repo `here <https://github.com/gravitl/netmaker/tree/master/kube/helm#values>`_ .
+
+Highly Available Installation (VMs/Bare Metal)
+==================================================
 
 For an enterprise Netmaker installation, you will need a server that is highly available, to ensure redundant WireGuard routing when any server goes down. To do this, you will need:
 
 1. A load balancer
 2. 3+ Netmaker server instances
-3. rqlite as the backing database
+3. rqlite or PostgreSQL as the backing database
 
 These documents outline general HA installation guidelines. Netmaker is highly customizable to meet a wide range of enterprise environments. If you would like support with an enterprise-grade Netmaker installation, you can `schedule a consultation here <https://gravitl.com/book>`_ . 
 
-The main consideration here is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.
+The main consideration for this document is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.
+
+If using PostgreSQL, follow their documentation for `installing in HA mode <https://www.postgresql.org/docs/14/high-availability.html>`_ and skip step #2.
 
 1. Load Balancer Setup
 ------------------------
@@ -398,7 +540,19 @@ Once rqlite instances have been configured, the Netmaker servers can be deployed
 3. Netmaker Setup
 ------------------
 
-Netmaker will be started on each node with default settings, except with DATABASE=rqlite and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.
+Netmaker will be started on each node with default settings, except with DATABASE=rqlite (or DATABASE=postgress) and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.
+
+If deploying HA with PostgreSQL, you will connect with the following settings:
+
+.. code-block::
+
+    SQL_HOST = <sql host>
+    SQL_PORT = <port>
+    SQL_DB   = <designated sql DB>
+    SQL_USER = <your user>
+    SQL_PASS = <your password>
+    DATABASE = postgres
+
 
 4. Other Considerations
 ------------------------
@@ -408,5 +562,3 @@ This is enough to get a functioning HA installation of Netmaker. However, you ma
 
 
 
-
-

+ 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.8.2',
+    VERSION: '0.8.4',
     LANGUAGE: 'None',
     COLLAPSE_INDEX: false,
     BUILDER: 'html',

+ 26 - 5
docs/_build/html/about.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>About &#8212; Netmaker 0.8.2 documentation</title>
+    <title>About &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -295,6 +295,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -482,6 +489,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

+ 26 - 5
docs/_build/html/api.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>API Reference &#8212; Netmaker 0.8.2 documentation</title>
+    <title>API Reference &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -462,6 +469,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

+ 35 - 14
docs/_build/html/architecture.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Architecture &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Architecture &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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 Install" href="quick-start.html" />
+    <link rel="next" title="Install" href="install.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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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,7 +268,7 @@
         </li>
         <li class="md-nav__item"><a href="#netclient" class="md-nav__link">Netclient</a>
         </li>
-        <li class="md-nav__item"><a href="#sqlite-and-rqlite" class="md-nav__link">sqlite and rqlite</a>
+        <li class="md-nav__item"><a href="#datavase-sqlite-rqlite-postgres" class="md-nav__link">Datavase (sqlite, rqlite, postgres)</a>
         </li>
         <li class="md-nav__item"><a href="#netmaker-ui" class="md-nav__link">Netmaker UI</a>
         </li>
@@ -325,6 +325,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -512,6 +519,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>
@@ -810,7 +831,7 @@
         </li>
         <li class="md-nav__item"><a href="#netclient" class="md-nav__link">Netclient</a>
         </li>
-        <li class="md-nav__item"><a href="#sqlite-and-rqlite" class="md-nav__link">sqlite and rqlite</a>
+        <li class="md-nav__item"><a href="#datavase-sqlite-rqlite-postgres" class="md-nav__link">Datavase (sqlite, rqlite, postgres)</a>
         </li>
         <li class="md-nav__item"><a href="#netmaker-ui" class="md-nav__link">Netmaker UI</a>
         </li>
@@ -882,10 +903,10 @@
 
 <h3 id="netmaker-server">Netmaker Server<a class="headerlink" href="#netmaker-server" title="Permalink to this headline">¶</a></h3>
 <p>The Netmaker server is, at its core, a golang binary. Source code can be found <a class="reference external" href="https://github.com/gravitl/netmaker">on GitHub</a>. The binary, by itself can be compiled for most systems. If you need to run the Netmaker server on a particular system, it likely can be made to work. In typical deployments, it is run as a Docker container. It can also be run as a systemd service as outlined in the non-docker install guide.</p>
-<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>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, 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 either sqlit (default) or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.</p>
+<p>The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.</p>
 
 
 <h3 id="netclient">Netclient<a class="headerlink" href="#netclient" title="Permalink to this headline">¶</a></h3>
@@ -898,8 +919,8 @@
 <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="sqlite-and-rqlite">sqlite and rqlite<a class="headerlink" href="#sqlite-and-rqlite" title="Permalink to this headline">¶</a></h3>
-<p>As of v0.8, Netmaker uses sqlite by default as a database. It can also use rqlite, a distributed (RAFT consensus) databaseand. Netmaker interacts with this database to store and retrieve information about nodes, networks, and users.</p>
+<h3 id="datavase-sqlite-rqlite-postgres">Datavase (sqlite, rqlite, postgres)<a class="headerlink" href="#datavase-sqlite-rqlite-postgres" title="Permalink to this headline">¶</a></h3>
+<p>As of v0.8, Netmaker uses sqlite by default as a database. It can also use PostgreSQL, or rqlite, a distributed (RAFT consensus) databaseand. Netmaker interacts with this database to store and retrieve information about nodes, networks, and users.</p>
 <p>Additional database support (besides sqlite and rqlite) is very easy to implement for special use cases. 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>
 
 
@@ -1002,12 +1023,12 @@
             </a>
           
           
-            <a href="quick-start.html" title="Quick Install"
+            <a href="install.html" title="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 Install </span>
+                class="md-footer-nav__direction"> Next </span> 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>

+ 26 - 5
docs/_build/html/client-installation.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Client Installation &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Client Installation &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -462,6 +469,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

+ 26 - 5
docs/_build/html/conduct.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Code of Conduct &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Code of Conduct &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -462,6 +469,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

+ 13 - 6
docs/_build/html/external-clients.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>External Clients &#8212; Netmaker 0.8.2 documentation</title>
+    <title>External Clients &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -473,7 +473,14 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
       
     
     </li></ul>

+ 13 - 6
docs/_build/html/genindex.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Index &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Index &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -471,7 +471,14 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
       
     
     </li></ul>

+ 26 - 5
docs/_build/html/getting-started.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Getting Started &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Getting Started &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -490,6 +497,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

+ 15 - 7
docs/_build/html/index.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Welcome to the Netmaker Documentation &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Welcome to the Netmaker Documentation &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="#" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="#" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="#" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="#"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -472,7 +472,14 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
       
     
     </li></ul>
@@ -888,7 +895,8 @@
 <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#nginx-reverse-proxy-setup-with-https">Nginx Reverse Proxy Setup with https</a></li>
-<li class="toctree-l2"><a class="reference internal" href="server-installation.html#highly-available-installation">Highly Available Installation</a></li>
+<li class="toctree-l2"><a class="reference internal" href="server-installation.html#highly-available-installation-kubernetes">Highly Available Installation (Kubernetes)</a></li>
+<li class="toctree-l2"><a class="reference internal" href="server-installation.html#highly-available-installation-vms-bare-metal">Highly Available Installation (VMs/Bare Metal)</a></li>
 </ul>
 </li>
 </ul>

+ 13 - 6
docs/_build/html/install.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Install &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Install &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -482,7 +482,14 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
       
     
     </li></ul>

+ 26 - 5
docs/_build/html/license.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>License &#8212; Netmaker 0.8.2 documentation</title>
+    <title>License &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -274,6 +274,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -461,6 +468,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

BIN
docs/_build/html/objects.inv


+ 26 - 5
docs/_build/html/quick-start-nginx.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Install with Nginx (depreciated) &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Install with Nginx (depreciated) &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -506,6 +513,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

+ 29 - 8
docs/_build/html/quick-start.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Quick Install &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Quick Install &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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="Getting Started" href="getting-started.html" />
-    <link rel="prev" title="Architecture" href="architecture.html" />
+    <link rel="prev" title="Install" href="install.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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -496,6 +503,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>
@@ -930,7 +951,7 @@
     <div class="md-footer-nav">
       <nav class="md-footer-nav__inner md-grid">
           
-            <a href="architecture.html" title="Architecture"
+            <a href="install.html" title="Install"
                class="md-flex md-footer-nav__link md-footer-nav__link--prev"
                rel="prev">
               <div class="md-flex__cell md-flex__cell--shrink">
@@ -939,7 +960,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> Architecture </span>
+                      class="md-footer-nav__direction"> Previous </span> Install </span>
               </div>
             </a>
           

+ 13 - 6
docs/_build/html/search.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Search &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Search &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -477,7 +477,14 @@
     <li class="md-nav__item">
     
     
-      <a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
       
     
     </li></ul>

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


+ 190 - 14
docs/_build/html/server-installation.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Advanced Server Installation &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Advanced Server Installation &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -467,7 +474,25 @@
         </li>
         <li class="md-nav__item"><a href="#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
         </li>
-        <li class="md-nav__item"><a href="#highly-available-installation" class="md-nav__link">Highly Available Installation</a><nav class="md-nav">
+        <li class="md-nav__item"><a href="#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#requirements" class="md-nav__link">Requirements</a>
+        </li>
+        <li class="md-nav__item"><a href="#recommended-settings" class="md-nav__link">Recommended Settings:</a>
+        </li>
+        <li class="md-nav__item"><a href="#example-installations" class="md-nav__link">Example Installations:</a>
+        </li>
+        <li class="md-nav__item"><a href="#ingress" class="md-nav__link">Ingress</a>
+        </li>
+        <li class="md-nav__item"><a href="#kernel-wireguard" class="md-nav__link">Kernel WireGuard</a>
+        </li>
+        <li class="md-nav__item"><a href="#dns" class="md-nav__link">DNS</a>
+        </li>
+        <li class="md-nav__item"><a href="#values" class="md-nav__link">Values</a>
+        </li></ul>
+            </nav>
+        </li>
+        <li class="md-nav__item"><a href="#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a><nav class="md-nav">
               <ul class="md-nav__list">
         <li class="md-nav__item"><a href="#load-balancer-setup" class="md-nav__link">1. Load Balancer Setup</a>
         </li>
@@ -536,7 +561,14 @@
     <li class="md-nav__item">
     
     
-      <a href="#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
+      <a href="#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
       
     
     </li></ul>
@@ -861,7 +893,25 @@
         </li>
         <li class="md-nav__item"><a href="#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
         </li>
-        <li class="md-nav__item"><a href="#highly-available-installation" class="md-nav__link">Highly Available Installation</a><nav class="md-nav">
+        <li class="md-nav__item"><a href="#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a><nav class="md-nav">
+              <ul class="md-nav__list">
+        <li class="md-nav__item"><a href="#requirements" class="md-nav__link">Requirements</a>
+        </li>
+        <li class="md-nav__item"><a href="#recommended-settings" class="md-nav__link">Recommended Settings:</a>
+        </li>
+        <li class="md-nav__item"><a href="#example-installations" class="md-nav__link">Example Installations:</a>
+        </li>
+        <li class="md-nav__item"><a href="#ingress" class="md-nav__link">Ingress</a>
+        </li>
+        <li class="md-nav__item"><a href="#kernel-wireguard" class="md-nav__link">Kernel WireGuard</a>
+        </li>
+        <li class="md-nav__item"><a href="#dns" class="md-nav__link">DNS</a>
+        </li>
+        <li class="md-nav__item"><a href="#values" class="md-nav__link">Values</a>
+        </li></ul>
+            </nav>
+        </li>
+        <li class="md-nav__item"><a href="#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a><nav class="md-nav">
               <ul class="md-nav__list">
         <li class="md-nav__item"><a href="#load-balancer-setup" class="md-nav__link">1. Load Balancer Setup</a>
         </li>
@@ -890,7 +940,7 @@
 
 <h2 id="system-compatibility">System Compatibility<a class="headerlink" href="#system-compatibility" title="Permalink to this headline">¶</a></h2>
 <p>Netmaker will require elevated privileges to perform network operations. Netmaker has similar limitations to <a class="reference internal" href="client-installation.html"><span class="doc">netclient</span></a> (client networking agent).</p>
-<p>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.</p>
+<p>Typically, Netmaker is run inside of containers (Docker). To run a non-docker installation, you must run the Netmaker binary, CoreDNS binary, database, and a web server directly on the host. Each of these components have their own individual requirements.</p>
 <p>The quick install guide is recommended for first-time installs.</p>
 <p>The following documents are meant for special cases like Kubernetes and LXC, or for more advanced setups.</p>
 
@@ -948,11 +998,26 @@
 <p><strong>Description:</strong> Enables DNS Mode, meaning config files will be generated for CoreDNS.</p>
 </dd>
 <dt>DATABASE:</dt><dd><p><strong>Default:</strong> “sqlite”</p>
-<p><strong>Description:</strong> Specify db type to connect with. Currently, options include “sqlite” and “rqlite”.</p>
+<p><strong>Description:</strong> Specify db type to connect with. Currently, options include “sqlite”, “rqlite”, and “postgres”.</p>
 </dd>
 <dt>SQL_CONN:</dt><dd><p><strong>Default:</strong> “<a class="reference external" href="http://">http://</a>”</p>
 <p><strong>Description:</strong> Specify the necessary string to connect with your local or remote sql database.</p>
 </dd>
+<dt>SQL_HOST:</dt><dd><p><strong>Default:</strong> “localhost”</p>
+<p><strong>Description:</strong> Host where postgres is running.</p>
+</dd>
+<dt>SQL_PORT:</dt><dd><p><strong>Default:</strong> “5432”</p>
+<p><strong>Description:</strong> port postgres is running.</p>
+</dd>
+<dt>SQL_DB:</dt><dd><p><strong>Default:</strong> “netmaker”</p>
+<p><strong>Description:</strong> DB to use in postgres.</p>
+</dd>
+<dt>SQL_USER:</dt><dd><p><strong>Default:</strong> “postgres”</p>
+<p><strong>Description:</strong> User for posgres.</p>
+</dd>
+<dt>SQL_PASS:</dt><dd><p><strong>Default:</strong> “nopass”</p>
+<p><strong>Description:</strong> Password for postgres.</p>
+</dd>
 <dt>CLIENT_MODE:</dt><dd><p><strong>Default:</strong> “on”</p>
 <p><strong>Description:</strong> Specifies if server should deploy itself as a node (client) in each network. May be turned to “off” for more restricted servers.</p>
 </dd>
@@ -1237,15 +1302,117 @@ kubectl apply -f netclient-template.yaml
 </div>
 
 
-<span id="hainstall"></span><h2 id="highly-available-installation">Highly Available Installation<a class="headerlink" href="#highly-available-installation" title="Permalink to this headline">¶</a></h2>
+<span id="hainstall"></span><h2 id="highly-available-installation-kubernetes">Highly Available Installation (Kubernetes)<a class="headerlink" href="#highly-available-installation-kubernetes" title="Permalink to this headline">¶</a></h2>
+<p>Netmaker comes with a Helm chart to deploy with High Availability on Kubernetes:</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">helm</span> <span class="n">repo</span> <span class="n">add</span> <span class="n">netmaker</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">gravitl</span><span class="o">.</span><span class="n">github</span><span class="o">.</span><span class="n">io</span><span class="o">/</span><span class="n">netmaker</span><span class="o">-</span><span class="n">helm</span><span class="o">/</span>
+<span class="n">helm</span> <span class="n">repo</span> <span class="n">update</span>
+</pre></div>
+</div>
+
+<h3 id="requirements">Requirements<a class="headerlink" href="#requirements" title="Permalink to this headline">¶</a></h3>
+<p>To run HA Netmaker on Kubernetes, your cluster must have the following:
+- RWO and RWX Storage Classes (RWX is only required if running Netmaker with DNS Management enabled).
+- An Ingress Controller and valid TLS certificates
+- This chart can currently generate ingress for Nginx or Traefik Ingress with LetsEncrypt + Cert Manager
+- If LetsEncrypt and CertManager are not deployed, you must manually configure certificates for your ingress</p>
+<p>Furthermore, the chart will by default install and use a postgresql cluster as its datastore.</p>
+
+
+<h3 id="recommended-settings">Recommended Settings:<a class="headerlink" href="#recommended-settings" title="Permalink to this headline">¶</a></h3>
+<p>A minimal HA install of Netmaker can be run with the following command:
+<cite>helm install netmaker –generate-name –set baseDomain=nm.example.com</cite>
+This install has some notable exceptions:
+- Ingress <strong>must</strong> be manually configured post-install (need to create valid Ingress with TLS)
+- Server will use “userspace” WireGuard, which is slower than kernel WG
+- DNS will be disabled</p>
+
+
+<h3 id="example-installations">Example Installations:<a class="headerlink" href="#example-installations" title="Permalink to this headline">¶</a></h3>
+<p>An annotated install command:</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">helm</span> <span class="n">install</span> <span class="n">netmaker</span><span class="o">/</span><span class="n">netmaker</span> <span class="o">--</span><span class="n">generate</span><span class="o">-</span><span class="n">name</span> \ <span class="c1"># generate a random id for the deploy</span>
+<span class="o">--</span><span class="nb">set</span> <span class="n">baseDomain</span><span class="o">=</span><span class="n">nm</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span> \ <span class="c1"># the base wildcard domain to use for the netmaker api/dashboard/grpc ingress</span>
+<span class="o">--</span><span class="nb">set</span> <span class="n">replicas</span><span class="o">=</span><span class="mi">3</span> \ <span class="c1"># number of server replicas to deploy (3 by default)</span>
+<span class="o">--</span><span class="nb">set</span> <span class="n">ingress</span><span class="o">.</span><span class="n">enabled</span><span class="o">=</span><span class="n">true</span> \ <span class="c1"># deploy ingress automatically (requires nginx or traefik and cert-manager + letsencrypt)</span>
+<span class="o">--</span><span class="nb">set</span> <span class="n">ingress</span><span class="o">.</span><span class="n">className</span><span class="o">=</span><span class="n">nginx</span> \ <span class="c1"># ingress class to use</span>
+<span class="o">--</span><span class="nb">set</span> <span class="n">ingress</span><span class="o">.</span><span class="n">tls</span><span class="o">.</span><span class="n">issuerName</span><span class="o">=</span><span class="n">letsencrypt</span><span class="o">-</span><span class="n">prod</span> \ <span class="c1"># LetsEncrypt certificate issuer to use</span>
+<span class="o">--</span><span class="nb">set</span> <span class="n">dns</span><span class="o">.</span><span class="n">enabled</span><span class="o">=</span><span class="n">true</span> \ <span class="c1"># deploy and enable private DNS management with CoreDNS</span>
+<span class="o">--</span><span class="nb">set</span> <span class="n">dns</span><span class="o">.</span><span class="n">clusterIP</span><span class="o">=</span><span class="mf">10.245</span><span class="o">.</span><span class="mf">75.75</span> <span class="o">--</span><span class="nb">set</span> <span class="n">dns</span><span class="o">.</span><span class="n">RWX</span><span class="o">.</span><span class="n">storageClassName</span><span class="o">=</span><span class="n">nfs</span> \ <span class="c1"># required fields for DNS</span>
+<span class="o">--</span><span class="nb">set</span> <span class="n">postgresql</span><span class="o">-</span><span class="n">ha</span><span class="o">.</span><span class="n">postgresql</span><span class="o">.</span><span class="n">replicaCount</span><span class="o">=</span><span class="mi">2</span> \ <span class="c1"># number of DB replicas to deploy (default 2)</span>
+</pre></div>
+</div>
+<p>The below command will install netmaker with two server replicas, a coredns server, and ingress with routes of api.nm.example.com, grpc.nm.example.com, and dashboard.nm.example.com. CoreDNS will be reachable at 10.245.75.75, and will use NFS to share a volume with Netmaker (to configure dns entries).</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">helm</span> <span class="n">install</span> <span class="n">netmaker</span><span class="o">/</span><span class="n">netmaker</span> <span class="o">--</span><span class="n">generate</span><span class="o">-</span><span class="n">name</span> <span class="o">--</span><span class="nb">set</span> <span class="n">baseDomain</span><span class="o">=</span><span class="n">nm</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span> \
+<span class="o">--</span><span class="nb">set</span> <span class="n">replicas</span><span class="o">=</span><span class="mi">2</span> <span class="o">--</span><span class="nb">set</span> <span class="n">ingress</span><span class="o">.</span><span class="n">enabled</span><span class="o">=</span><span class="n">true</span> <span class="o">--</span><span class="nb">set</span> <span class="n">dns</span><span class="o">.</span><span class="n">enabled</span><span class="o">=</span><span class="n">true</span> \
+<span class="o">--</span><span class="nb">set</span> <span class="n">dns</span><span class="o">.</span><span class="n">clusterIP</span><span class="o">=</span><span class="mf">10.245</span><span class="o">.</span><span class="mf">75.75</span> <span class="o">--</span><span class="nb">set</span> <span class="n">dns</span><span class="o">.</span><span class="n">RWX</span><span class="o">.</span><span class="n">storageClassName</span><span class="o">=</span><span class="n">nfs</span> \
+<span class="o">--</span><span class="nb">set</span> <span class="n">ingress</span><span class="o">.</span><span class="n">className</span><span class="o">=</span><span class="n">nginx</span>
+</pre></div>
+</div>
+<p>The below command will install netmaker with three server replicas (the default), <strong>no coredns</strong>, and ingress with routes of api.netmaker.example.com, grpc.netmaker.example.com, and dashboard.netmaker.example.com. There will be one UI replica instead of two, and one database instance instead of two. Traefik will look for a ClusterIssuer named “le-prod-2” to get valid certificates for the ingress.</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">helm3</span> <span class="n">install</span> <span class="n">netmaker</span><span class="o">/</span><span class="n">netmaker</span> <span class="o">--</span><span class="n">generate</span><span class="o">-</span><span class="n">name</span> \
+<span class="o">--</span><span class="nb">set</span> <span class="n">baseDomain</span><span class="o">=</span><span class="n">netmaker</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span> <span class="o">--</span><span class="nb">set</span> <span class="n">postgresql</span><span class="o">-</span><span class="n">ha</span><span class="o">.</span><span class="n">postgresql</span><span class="o">.</span><span class="n">replicaCount</span><span class="o">=</span><span class="mi">1</span> \
+<span class="o">--</span><span class="nb">set</span> <span class="n">ui</span><span class="o">.</span><span class="n">replicas</span><span class="o">=</span><span class="mi">1</span> <span class="o">--</span><span class="nb">set</span> <span class="n">ingress</span><span class="o">.</span><span class="n">enabled</span><span class="o">=</span><span class="n">true</span> \
+<span class="o">--</span><span class="nb">set</span> <span class="n">ingress</span><span class="o">.</span><span class="n">tls</span><span class="o">.</span><span class="n">issuerName</span><span class="o">=</span><span class="n">le</span><span class="o">-</span><span class="n">prod</span><span class="o">-</span><span class="mi">2</span> <span class="o">--</span><span class="nb">set</span> <span class="n">ingress</span><span class="o">.</span><span class="n">className</span><span class="o">=</span><span class="n">traefik</span>
+</pre></div>
+</div>
+<p>Below, we discuss the considerations for Ingress, Kernel WireGuard, and DNS.</p>
+
+
+<h3 id="ingress">Ingress<a class="headerlink" href="#ingress" title="Permalink to this headline">¶</a></h3>
+<p>To run HA Netmaker, you must have ingress installed and enabled on your cluster with valid TLS certificates (not self-signed). If you are running Nginx as your Ingress Controller and LetsEncrypt for TLS certificate management, you can run the helm install with the following settings:</p>
+<ul class="simple">
+<li><p><cite>–set ingress.enabled=true</cite></p></li>
+<li><p><cite>–set ingress.annotations.cert-manager.io/cluster-issuer=&lt;your LE issuer name&gt;</cite></p></li>
+</ul>
+<p>If you are not using Nginx or Traefik and LetsEncrypt, we recommend leaving ingress.enabled=false (default), and then manually creating the ingress objects post-install. You will need three ingress objects with TLS:</p>
+<ul class="simple">
+<li><p><cite>dashboard.&lt;baseDomain&gt;</cite></p></li>
+<li><p><cite>api.&lt;baseDomain&gt;</cite></p></li>
+<li><p><cite>grpc.&lt;baseDomain&gt;</cite></p></li>
+</ul>
+<p>If deploying manually, the gRPC ingress object requires special considerations. Look up the proper way to route grpc with your ingress controller. For instance, on Traefik, an IngressRouteTCP object is required.</p>
+<p>There are some example ingress objects in the kube/example folder.</p>
+
+
+<h3 id="kernel-wireguard">Kernel WireGuard<a class="headerlink" href="#kernel-wireguard" title="Permalink to this headline">¶</a></h3>
+<p>If you have control of the Kubernetes worker node servers, we recommend <strong>first</strong> installing WireGuard on the hosts, and then installing HA Netmaker in Kernel mode. By default, Netmaker will install with userspace WireGuard (wireguard-go) for maximum compatibility, and to avoid needing permissions at the host level. If you have installed WireGuard on your hosts, you should install Netmaker’s helm chart with the following option:</p>
+<ul class="simple">
+<li><p><cite>–set wireguard.kernel=true</cite></p></li>
+</ul>
+
+
+<h3 id="dns">DNS<a class="headerlink" href="#dns" title="Permalink to this headline">¶</a></h3>
+<p>By Default, the helm chart will deploy without DNS enabled. To enable DNS, specify with:</p>
+<ul class="simple">
+<li><p><cite>–set dns.enabled=true</cite></p></li>
+</ul>
+<p>This will require specifying a RWX storage class, e.g.:</p>
+<ul class="simple">
+<li><p><cite>–set dns.RWX.storageClassName=nfs</cite></p></li>
+</ul>
+<p>This will also require specifying a service address for DNS. Choose a valid ipv4 address from the service IP CIDR for your cluster, e.g.:</p>
+<ul class="simple">
+<li><p><cite>–set dns.clusterIP=10.245.69.69</cite></p></li>
+</ul>
+<p><strong>This address will only be reachable from hosts that have access to the cluster service CIDR.</strong> It is only designed for use cases related to k8s. If you want a more general-use Netmaker server on Kubernetes for use cases outside of k8s, you will need to do one of the following:
+- bind the CoreDNS service to port 53 on one of your worker nodes and set the COREDNS_ADDRESS equal to the public IP of the worker node
+- Create a private Network with Netmaker and set the COREDNS_ADDRESS equal to the private address of the host running CoreDNS. For this, CoreDNS will need a node selector and will ideally run on the same host as one of the Netmaker server instances.</p>
+
+
+<h3 id="values">Values<a class="headerlink" href="#values" title="Permalink to this headline">¶</a></h3>
+<p>To view all options for the chart, please visit the README in the code repo <a class="reference external" href="https://github.com/gravitl/netmaker/tree/master/kube/helm#values">here</a> .</p>
+
+
+
+<h2 id="highly-available-installation-vms-bare-metal">Highly Available Installation (VMs/Bare Metal)<a class="headerlink" href="#highly-available-installation-vms-bare-metal" title="Permalink to this headline">¶</a></h2>
 <p>For an enterprise Netmaker installation, you will need a server that is highly available, to ensure redundant WireGuard routing when any server goes down. To do this, you will need:</p>
 <ol class="arabic simple">
 <li><p>A load balancer</p></li>
 <li><p>3+ Netmaker server instances</p></li>
-<li><p>rqlite as the backing database</p></li>
+<li><p>rqlite or PostgreSQL as the backing database</p></li>
 </ol>
 <p>These documents outline general HA installation guidelines. Netmaker is highly customizable to meet a wide range of enterprise environments. If you would like support with an enterprise-grade Netmaker installation, you can <a class="reference external" href="https://gravitl.com/book">schedule a consultation here</a> .</p>
-<p>The main consideration here is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.</p>
+<p>The main consideration for this document is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.</p>
+<p>If using PostgreSQL, follow their documentation for <a class="reference external" href="https://www.postgresql.org/docs/14/high-availability.html">installing in HA mode</a> and skip step #2.</p>
 
 <h3 id="load-balancer-setup">1. Load Balancer Setup<a class="headerlink" href="#load-balancer-setup" title="Permalink to this headline">¶</a></h3>
 <p>Your load balancer of choice will send requests to the Netmaker servers. Setup is similar to the various guides we have created for Nginx, Caddy, and Traefik. SSL certificates must also be configured and handled by the LB.</p>
@@ -1277,7 +1444,16 @@ kubectl apply -f netclient-template.yaml
 
 
 <h3 id="netmaker-setup">3. Netmaker Setup<a class="headerlink" href="#netmaker-setup" title="Permalink to this headline">¶</a></h3>
-<p>Netmaker will be started on each node with default settings, except with DATABASE=rqlite and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.</p>
+<p>Netmaker will be started on each node with default settings, except with DATABASE=rqlite (or DATABASE=postgress) and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.</p>
+<p>If deploying HA with PostgreSQL, you will connect with the following settings:</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">SQL_HOST</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">sql</span> <span class="n">host</span><span class="o">&gt;</span>
+<span class="n">SQL_PORT</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">port</span><span class="o">&gt;</span>
+<span class="n">SQL_DB</span>   <span class="o">=</span> <span class="o">&lt;</span><span class="n">designated</span> <span class="n">sql</span> <span class="n">DB</span><span class="o">&gt;</span>
+<span class="n">SQL_USER</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">your</span> <span class="n">user</span><span class="o">&gt;</span>
+<span class="n">SQL_PASS</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">your</span> <span class="n">password</span><span class="o">&gt;</span>
+<span class="n">DATABASE</span> <span class="o">=</span> <span class="n">postgres</span>
+</pre></div>
+</div>
 
 
 <h3 id="other-considerations">4. Other Considerations<a class="headerlink" href="#other-considerations" title="Permalink to this headline">¶</a></h3>

+ 26 - 5
docs/_build/html/support.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Support &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Support &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -462,6 +469,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

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

@@ -46,7 +46,7 @@
   
   
   
-    <title>Troubleshooting &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Troubleshooting &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -462,6 +469,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

+ 26 - 5
docs/_build/html/usage.html

@@ -46,7 +46,7 @@
   
   
   
-    <title>Using Netmaker &#8212; Netmaker 0.8.2 documentation</title>
+    <title>Using Netmaker &#8212; Netmaker 0.8.4 documentation</title>
     <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
     <link rel="stylesheet" type="text/css" href="_static/material.css" />
     <script data-url_root="./" id="documentation_options" 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.8.2 documentation"
+        <a href="index.html" title="Netmaker 0.8.4 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.8.2 documentation</a></li>
+          <li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.4 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.8.2 documentation" class="md-nav__button md-logo">
+    <a href="index.html" title="Netmaker 0.8.4 documentation" class="md-nav__button md-logo">
       
         <i class="md-icon">&#xe869</i>
       
     </a>
     <a href="index.html"
-       title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
+       title="Netmaker 0.8.4 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">
@@ -275,6 +275,13 @@
     
     </li></ul>
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="install.html" class="md-nav__link">Install</a>
+      
+    
     </li>
     <li class="md-nav__item">
     
@@ -462,6 +469,20 @@
       <a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
       
     
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-kubernetes" class="md-nav__link">Highly Available Installation (Kubernetes)</a>
+      
+    
+    </li>
+    <li class="md-nav__item">
+    
+    
+      <a href="server-installation.html#highly-available-installation-vms-bare-metal" class="md-nav__link">Highly Available Installation (VMs/Bare Metal)</a>
+      
+    
     </li></ul>
     
     </li>

+ 5 - 5
docs/architecture.rst

@@ -77,13 +77,13 @@ Netmaker Server
 
 The Netmaker server is, at its core, a golang binary. Source code can be found `on GitHub <https://github.com/gravitl/netmaker>`_. The binary, by itself can be compiled for most systems. If you need to run the Netmaker server on a particular system, it likely can be made to work. In typical deployments, it is run as a Docker container. It can also be run as a systemd service as outlined in the non-docker install guide.
 
-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).
+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, 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).
 
 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.
 
 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 either sqlit (default) or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.
+The Netmaker server interacts with either sqlite (default), postgres, or rqlite, a distributed version of sqlite, as its database. This DB holds information about nodes, networks, users, and other important data. This data is configuration data. For the most part, Netmaker serves configuration data to Nodes, telling them how they should configure themselves. The Netclient is the agent that actually does that configuration.
 
 
 Netclient
@@ -104,10 +104,10 @@ If running in daemon mode, on a periodic basis (systemd timer), the netclient pe
 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.
 
 
-sqlite and rqlite
----------------------
+Datavase (sqlite, rqlite, postgres)
+-------------------------------------
 
-As of v0.8, Netmaker uses sqlite by default as a database. It can also use rqlite, a distributed (RAFT consensus) databaseand. Netmaker interacts with this database to store and retrieve information about nodes, networks, and users. 
+As of v0.8, Netmaker uses sqlite by default as a database. It can also use PostgreSQL, or rqlite, a distributed (RAFT consensus) databaseand. Netmaker interacts with this database to store and retrieve information about nodes, networks, and users. 
 
 Additional database support (besides sqlite and rqlite) is very easy to implement for special use cases. 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.
 

+ 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.8.3'
+release = '0.8.4'
 
 
 # -- General configuration ---------------------------------------------------

+ 162 - 10
docs/server-installation.rst

@@ -9,7 +9,7 @@ System Compatibility
 
 Netmaker will require elevated privileges to perform network operations. Netmaker has similar limitations to :doc:`netclient <./client-installation>` (client networking agent). 
 
-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.
+Typically, Netmaker is run inside of containers (Docker). To run a non-docker installation, you must run the Netmaker binary, CoreDNS binary, database, and a web server directly on the host. Each of these components have their own individual requirements.
 
 The quick install guide is recommended for first-time installs. 
 
@@ -101,13 +101,38 @@ DNS_MODE:
 DATABASE:  
     **Default:** "sqlite"
 
-    **Description:** Specify db type to connect with. Currently, options include "sqlite" and "rqlite".
+    **Description:** Specify db type to connect with. Currently, options include "sqlite", "rqlite", and "postgres".
 
-SQL_CONN:  
+SQL_CONN:
     **Default:** "http://"
 
     **Description:** Specify the necessary string to connect with your local or remote sql database.
 
+SQL_HOST:
+    **Default:** "localhost"
+
+    **Description:** Host where postgres is running.
+
+SQL_PORT:
+    **Default:** "5432"
+
+    **Description:** port postgres is running.
+
+SQL_DB:
+    **Default:** "netmaker"
+
+    **Description:** DB to use in postgres.
+
+SQL_USER:
+    **Default:** "postgres"
+
+    **Description:** User for posgres.
+
+SQL_PASS:
+    **Default:** "nopass"
+
+    **Description:** Password for postgres.
+
 CLIENT_MODE:  
     **Default:** "on"
 
@@ -344,18 +369,135 @@ The following file configures Netmaker as a subdomain. This config is an adaptio
 
 .. _HAInstall:
 
-Highly Available Installation
-===============================
+
+
+Highly Available Installation (Kubernetes)
+==================================================
+
+Netmaker comes with a Helm chart to deploy with High Availability on Kubernetes:
+
+.. code-block::
+
+    helm repo add netmaker https://gravitl.github.io/netmaker-helm/
+    helm repo update
+
+Requirements
+---------------
+
+To run HA Netmaker on Kubernetes, your cluster must have the following:
+- RWO and RWX Storage Classes (RWX is only required if running Netmaker with DNS Management enabled).
+- An Ingress Controller and valid TLS certificates 
+- This chart can currently generate ingress for Nginx or Traefik Ingress with LetsEncrypt + Cert Manager
+- If LetsEncrypt and CertManager are not deployed, you must manually configure certificates for your ingress
+
+Furthermore, the chart will by default install and use a postgresql cluster as its datastore.
+
+Recommended Settings:
+----------------------
+A minimal HA install of Netmaker can be run with the following command:
+`helm install netmaker --generate-name --set baseDomain=nm.example.com`
+This install has some notable exceptions:
+- Ingress **must** be manually configured post-install (need to create valid Ingress with TLS)
+- Server will use "userspace" WireGuard, which is slower than kernel WG
+- DNS will be disabled
+
+Example Installations:
+------------------------
+An annotated install command:
+
+.. code-block::
+
+    helm install netmaker/netmaker --generate-name \ # generate a random id for the deploy 
+    --set baseDomain=nm.example.com \ # the base wildcard domain to use for the netmaker api/dashboard/grpc ingress 
+    --set replicas=3 \ # number of server replicas to deploy (3 by default) 
+    --set ingress.enabled=true \ # deploy ingress automatically (requires nginx or traefik and cert-manager + letsencrypt) 
+    --set ingress.className=nginx \ # ingress class to use 
+    --set ingress.tls.issuerName=letsencrypt-prod \ # LetsEncrypt certificate issuer to use 
+    --set dns.enabled=true \ # deploy and enable private DNS management with CoreDNS 
+    --set dns.clusterIP=10.245.75.75 --set dns.RWX.storageClassName=nfs \ # required fields for DNS 
+    --set postgresql-ha.postgresql.replicaCount=2 \ # number of DB replicas to deploy (default 2)
+
+
+The below command will install netmaker with two server replicas, a coredns server, and ingress with routes of api.nm.example.com, grpc.nm.example.com, and dashboard.nm.example.com. CoreDNS will be reachable at 10.245.75.75, and will use NFS to share a volume with Netmaker (to configure dns entries).
+
+.. code-block::
+
+    helm install netmaker/netmaker --generate-name --set baseDomain=nm.example.com \
+    --set replicas=2 --set ingress.enabled=true --set dns.enabled=true \
+    --set dns.clusterIP=10.245.75.75 --set dns.RWX.storageClassName=nfs \
+    --set ingress.className=nginx
+
+The below command will install netmaker with three server replicas (the default), **no coredns**, and ingress with routes of api.netmaker.example.com, grpc.netmaker.example.com, and dashboard.netmaker.example.com. There will be one UI replica instead of two, and one database instance instead of two. Traefik will look for a ClusterIssuer named "le-prod-2" to get valid certificates for the ingress. 
+
+.. code-block::
+
+    helm3 install netmaker/netmaker --generate-name \
+    --set baseDomain=netmaker.example.com --set postgresql-ha.postgresql.replicaCount=1 \
+    --set ui.replicas=1 --set ingress.enabled=true \
+    --set ingress.tls.issuerName=le-prod-2 --set ingress.className=traefik
+
+Below, we discuss the considerations for Ingress, Kernel WireGuard, and DNS.
+
+Ingress	
+----------
+To run HA Netmaker, you must have ingress installed and enabled on your cluster with valid TLS certificates (not self-signed). If you are running Nginx as your Ingress Controller and LetsEncrypt for TLS certificate management, you can run the helm install with the following settings:
+
+- `--set ingress.enabled=true`
+- `--set ingress.annotations.cert-manager.io/cluster-issuer=<your LE issuer name>`
+
+If you are not using Nginx or Traefik and LetsEncrypt, we recommend leaving ingress.enabled=false (default), and then manually creating the ingress objects post-install. You will need three ingress objects with TLS:
+
+- `dashboard.<baseDomain>`
+- `api.<baseDomain>`
+- `grpc.<baseDomain>`
+
+If deploying manually, the gRPC ingress object requires special considerations. Look up the proper way to route grpc with your ingress controller. For instance, on Traefik, an IngressRouteTCP object is required.
+
+There are some example ingress objects in the kube/example folder.
+
+Kernel WireGuard
+------------------
+If you have control of the Kubernetes worker node servers, we recommend **first** installing WireGuard on the hosts, and then installing HA Netmaker in Kernel mode. By default, Netmaker will install with userspace WireGuard (wireguard-go) for maximum compatibility, and to avoid needing permissions at the host level. If you have installed WireGuard on your hosts, you should install Netmaker's helm chart with the following option:
+
+- `--set wireguard.kernel=true`
+
+DNS
+----------
+By Default, the helm chart will deploy without DNS enabled. To enable DNS, specify with:
+
+- `--set dns.enabled=true` 
+
+This will require specifying a RWX storage class, e.g.:
+
+- `--set dns.RWX.storageClassName=nfs`
+
+This will also require specifying a service address for DNS. Choose a valid ipv4 address from the service IP CIDR for your cluster, e.g.:
+
+- `--set dns.clusterIP=10.245.69.69`
+
+**This address will only be reachable from hosts that have access to the cluster service CIDR.** It is only designed for use cases related to k8s. If you want a more general-use Netmaker server on Kubernetes for use cases outside of k8s, you will need to do one of the following:
+- bind the CoreDNS service to port 53 on one of your worker nodes and set the COREDNS_ADDRESS equal to the public IP of the worker node
+- Create a private Network with Netmaker and set the COREDNS_ADDRESS equal to the private address of the host running CoreDNS. For this, CoreDNS will need a node selector and will ideally run on the same host as one of the Netmaker server instances.
+
+Values
+---------
+
+To view all options for the chart, please visit the README in the code repo `here <https://github.com/gravitl/netmaker/tree/master/kube/helm#values>`_ .
+
+Highly Available Installation (VMs/Bare Metal)
+==================================================
 
 For an enterprise Netmaker installation, you will need a server that is highly available, to ensure redundant WireGuard routing when any server goes down. To do this, you will need:
 
 1. A load balancer
 2. 3+ Netmaker server instances
-3. rqlite as the backing database
+3. rqlite or PostgreSQL as the backing database
 
 These documents outline general HA installation guidelines. Netmaker is highly customizable to meet a wide range of enterprise environments. If you would like support with an enterprise-grade Netmaker installation, you can `schedule a consultation here <https://gravitl.com/book>`_ . 
 
-The main consideration here is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.
+The main consideration for this document is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.
+
+If using PostgreSQL, follow their documentation for `installing in HA mode <https://www.postgresql.org/docs/14/high-availability.html>`_ and skip step #2.
 
 1. Load Balancer Setup
 ------------------------
@@ -398,7 +540,19 @@ Once rqlite instances have been configured, the Netmaker servers can be deployed
 3. Netmaker Setup
 ------------------
 
-Netmaker will be started on each node with default settings, except with DATABASE=rqlite and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.
+Netmaker will be started on each node with default settings, except with DATABASE=rqlite (or DATABASE=postgress) and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.
+
+If deploying HA with PostgreSQL, you will connect with the following settings:
+
+.. code-block::
+
+    SQL_HOST = <sql host>
+    SQL_PORT = <port>
+    SQL_DB   = <designated sql DB>
+    SQL_USER = <your user>
+    SQL_PASS = <your password>
+    DATABASE = postgres
+
 
 4. Other Considerations
 ------------------------
@@ -408,5 +562,3 @@ This is enough to get a functioning HA installation of Netmaker. However, you ma
 
 
 
-
-

+ 110 - 0
logic/network.go

@@ -0,0 +1,110 @@
+package logic
+
+import (
+	"net"
+	"os/exec"
+	"strings"
+
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+// GetLocalIP - gets the local ip
+func GetLocalIP(node models.Node) string {
+
+	var local string
+
+	ifaces, err := net.Interfaces()
+	if err != nil {
+		return local
+	}
+	_, localrange, err := net.ParseCIDR(node.LocalRange)
+	if err != nil {
+		return local
+	}
+
+	found := false
+	for _, i := range ifaces {
+		if i.Flags&net.FlagUp == 0 {
+			continue // interface down
+		}
+		if i.Flags&net.FlagLoopback != 0 {
+			continue // loopback interface
+		}
+		addrs, err := i.Addrs()
+		if err != nil {
+			return local
+		}
+		for _, addr := range addrs {
+			var ip net.IP
+			switch v := addr.(type) {
+			case *net.IPNet:
+				if !found {
+					ip = v.IP
+					local = ip.String()
+					if node.IsLocal == "yes" {
+						found = localrange.Contains(ip)
+					} else {
+						found = true
+					}
+				}
+			case *net.IPAddr:
+				if !found {
+					ip = v.IP
+					local = ip.String()
+					if node.IsLocal == "yes" {
+						found = localrange.Contains(ip)
+
+					} else {
+						found = true
+					}
+				}
+			}
+		}
+	}
+	return local
+}
+
+// == Private ==
+
+func deleteInterface(ifacename string, postdown string) error {
+	var err error
+	if !ncutils.IsKernel() {
+		err = RemoveConf(ifacename, true)
+	} else {
+		ipExec, errN := exec.LookPath("ip")
+		err = errN
+		if err != nil {
+			ncutils.PrintLog(err.Error(), 1)
+		}
+		_, err = ncutils.RunCmd(ipExec+" link del "+ifacename, false)
+		if postdown != "" {
+			runcmds := strings.Split(postdown, "; ")
+			err = ncutils.RunCmds(runcmds, true)
+		}
+	}
+	return err
+}
+
+func isInterfacePresent(iface string, address string) (string, bool) {
+	var interfaces []net.Interface
+	var err error
+	interfaces, err = net.Interfaces()
+	if err != nil {
+		Log("ERROR: could not read interfaces", 0)
+		return "", true
+	}
+	for _, currIface := range interfaces {
+		var currAddrs []net.Addr
+		currAddrs, err = currIface.Addrs()
+		if err != nil || len(currAddrs) == 0 {
+			continue
+		}
+		for _, addr := range currAddrs {
+			if strings.Contains(addr.String(), address) && currIface.Name != iface {
+				return currIface.Name, false
+			}
+		}
+	}
+	return "", true
+}

+ 473 - 0
logic/server.go

@@ -0,0 +1,473 @@
+package logic
+
+import (
+	"errors"
+	"net"
+	"os"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+	"github.com/gravitl/netmaker/servercfg"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+)
+
+// == Join, Checkin, and Leave for Server ==
+
+// KUBERNETES_LISTEN_PORT - starting port for Kubernetes in order to use NodePort range
+const KUBERNETES_LISTEN_PORT = 31821
+const KUBERNETES_SERVER_MTU = 1024
+
+// ServerJoin - responsible for joining a server to a network
+func ServerJoin(network string, serverID string, privateKey string) error {
+
+	if network == "" {
+		return errors.New("no network provided")
+	}
+
+	var err error
+	var node *models.Node // fill this object with server node specifics
+	node = &models.Node{
+		IsServer:     "yes",
+		DNSOn:        "no",
+		IsStatic:     "yes",
+		Name:         models.NODE_SERVER_NAME,
+		MacAddress:   serverID,
+		UDPHolePunch: "no",
+	}
+	node.SetDefaults()
+
+	if servercfg.GetPlatform() == "Kubernetes" {
+		node.ListenPort = KUBERNETES_LISTEN_PORT
+		node.MTU = KUBERNETES_SERVER_MTU
+	}
+
+	if node.LocalRange != "" && node.LocalAddress == "" {
+		Log("local vpn, getting local address from range: "+node.LocalRange, 1)
+		node.LocalAddress = GetLocalIP(*node)
+	}
+
+	if node.Endpoint == "" {
+		if node.IsLocal == "yes" && node.LocalAddress != "" {
+			node.Endpoint = node.LocalAddress
+		} else {
+			node.Endpoint, err = ncutils.GetPublicIP()
+		}
+		if err != nil || node.Endpoint == "" {
+			Log("Error setting server node Endpoint.", 0)
+			return err
+		}
+	}
+
+	// Generate and set public/private WireGuard Keys
+	if privateKey == "" {
+		wgPrivatekey, err := wgtypes.GeneratePrivateKey()
+		if err != nil {
+			Log(err.Error(), 1)
+			return err
+		}
+		privateKey = wgPrivatekey.String()
+		node.PublicKey = wgPrivatekey.PublicKey().String()
+	}
+	// should never set mac address for server anymore
+
+	var postnode *models.Node
+	postnode = &models.Node{
+		Password:            node.Password,
+		MacAddress:          node.MacAddress,
+		AccessKey:           node.AccessKey,
+		Network:             network,
+		ListenPort:          node.ListenPort,
+		PostUp:              node.PostUp,
+		PostDown:            node.PostDown,
+		PersistentKeepalive: node.PersistentKeepalive,
+		LocalAddress:        node.LocalAddress,
+		Interface:           node.Interface,
+		PublicKey:           node.PublicKey,
+		DNSOn:               node.DNSOn,
+		Name:                node.Name,
+		Endpoint:            node.Endpoint,
+		SaveConfig:          node.SaveConfig,
+		UDPHolePunch:        node.UDPHolePunch,
+	}
+
+	Log("adding a server instance on network "+postnode.Network, 2)
+	*node, err = CreateNode(*postnode, network)
+	if err != nil {
+		return err
+	}
+	err = SetNetworkNodesLastModified(node.Network)
+	if err != nil {
+		return err
+	}
+
+	// get free port based on returned default listen port
+	node.ListenPort, err = ncutils.GetFreePort(node.ListenPort)
+	if err != nil {
+		Log("Error retrieving port: "+err.Error(), 2)
+	}
+
+	// safety check. If returned node from server is local, but not currently configured as local, set to local addr
+	if node.IsLocal == "yes" && node.LocalRange != "" {
+		node.LocalAddress, err = ncutils.GetLocalIP(node.LocalRange)
+		if err != nil {
+			return err
+		}
+		node.Endpoint = node.LocalAddress
+	}
+
+	node.SetID()
+	if err = StorePrivKey(node.ID, privateKey); err != nil {
+		return err
+	}
+	if err = ServerPush(node.MacAddress, node.Network); err != nil {
+		return err
+	}
+
+	peers, hasGateway, gateways, err := GetServerPeers(node.MacAddress, network, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
+	if err != nil && !ncutils.IsEmptyRecord(err) {
+		Log("failed to retrieve peers", 1)
+		return err
+	}
+
+	err = initWireguard(node, privateKey, peers, hasGateway, gateways)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// ServerCheckin - runs pulls and pushes for server
+func ServerCheckin(mac string, network string) error {
+	var serverNode models.Node
+	var newNode *models.Node
+	var err error
+	serverNode, err = GetNode(mac, network)
+	if err != nil {
+		return err
+	}
+
+	newNode, err = ServerPull(mac, network, false)
+	if isDeleteError(err) {
+		return ServerLeave(mac, network)
+	} else if err != nil {
+		return err
+	}
+
+	actionCompleted := checkNodeActions(newNode, network, &serverNode)
+	if actionCompleted == models.NODE_DELETE {
+		return errors.New("node has been removed")
+	}
+
+	return ServerPush(newNode.MacAddress, newNode.Network)
+}
+
+// ServerPull - pulls current config/peers for server
+func ServerPull(mac string, network string, onErr bool) (*models.Node, error) {
+
+	var serverNode models.Node
+	var err error
+	serverNode, err = GetNode(mac, network)
+	if err != nil {
+		return &serverNode, err
+	}
+
+	if serverNode.IPForwarding == "yes" {
+		if err = setIPForwardingLinux(); err != nil {
+			return &serverNode, err
+		}
+	}
+	serverNode.OS = runtime.GOOS
+
+	if serverNode.PullChanges == "yes" || onErr {
+		// check for interface change
+		var isIfacePresent bool
+		var oldIfaceName string
+		// checks if address is in use by another interface
+		oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
+		if !isIfacePresent {
+			if err = deleteInterface(oldIfaceName, serverNode.PostDown); err != nil {
+				Log("could not delete old interface "+oldIfaceName, 1)
+			}
+			Log("removed old interface "+oldIfaceName, 1)
+		}
+		serverNode.PullChanges = "no"
+		if err = setWGConfig(serverNode, network, false); err != nil {
+			return &serverNode, err
+		}
+		// handle server side update
+		if err = serverNode.Update(&serverNode); err != nil {
+			return &serverNode, err
+		}
+	} else {
+		if err = setWGConfig(serverNode, network, true); err != nil {
+			if errors.Is(err, os.ErrNotExist) {
+				return ServerPull(serverNode.MacAddress, serverNode.Network, true)
+			} else {
+				return &serverNode, err
+			}
+		}
+	}
+
+	return &serverNode, nil
+}
+
+// ServerPush - pushes config changes for server checkins/join
+func ServerPush(mac string, network string) error {
+
+	var serverNode models.Node
+	var err error
+	serverNode, err = GetNode(mac, network)
+	if err != nil /* && !ncutils.IsEmptyRecord(err) May not be necessary */ {
+		return err
+	}
+	serverNode.OS = runtime.GOOS
+	serverNode.SetLastCheckIn()
+	return serverNode.Update(&serverNode)
+}
+
+// ServerLeave - removes a server node
+func ServerLeave(mac string, network string) error {
+
+	var serverNode models.Node
+	var err error
+	serverNode, err = GetNode(mac, network)
+	if err != nil {
+		return err
+	}
+	serverNode.SetID()
+	return DeleteNode(serverNode.ID, true)
+}
+
+// GetServerPeers - gets peers of server
+func GetServerPeers(macaddress string, network string, dualstack bool, isIngressGateway bool) ([]wgtypes.PeerConfig, bool, []string, error) {
+	hasGateway := false
+	var err error
+	var gateways []string
+	var peers []wgtypes.PeerConfig
+	var nodecfg models.Node
+	var nodes []models.Node // fill above fields from server or client
+
+	nodecfg, err = GetNode(macaddress, network)
+	if err != nil {
+		return nil, hasGateway, gateways, err
+	}
+	nodes, err = GetPeers(nodecfg)
+	if err != nil {
+		return nil, hasGateway, gateways, err
+	}
+
+	keepalive := nodecfg.PersistentKeepalive
+	keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
+	keepaliveserver, err := time.ParseDuration(strconv.FormatInt(int64(5), 10) + "s")
+	if err != nil {
+		Log("Issue with format of keepalive value. Please view server config. "+err.Error(), 1)
+		return nil, hasGateway, gateways, err
+	}
+
+	for _, node := range nodes {
+		pubkey, err := wgtypes.ParseKey(node.PublicKey)
+		if err != nil {
+			Log("error parsing key "+pubkey.String(), 1)
+			return peers, hasGateway, gateways, err
+		}
+
+		if nodecfg.PublicKey == node.PublicKey {
+			continue
+		}
+		if nodecfg.Endpoint == node.Endpoint {
+			if nodecfg.LocalAddress != node.LocalAddress && node.LocalAddress != "" {
+				node.Endpoint = node.LocalAddress
+			} else {
+				continue
+			}
+		}
+
+		var peer wgtypes.PeerConfig
+		var peeraddr = net.IPNet{
+			IP:   net.ParseIP(node.Address),
+			Mask: net.CIDRMask(32, 32),
+		}
+		var allowedips []net.IPNet
+		allowedips = append(allowedips, peeraddr)
+		// handle manually set peers
+		for _, allowedIp := range node.AllowedIPs {
+			if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
+				nodeEndpointArr := strings.Split(node.Endpoint, ":")
+				if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != node.Address { // don't need to add an allowed ip that already exists..
+					allowedips = append(allowedips, *ipnet)
+				}
+			} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != node.Address {
+				ipnet := net.IPNet{
+					IP:   net.ParseIP(allowedIp),
+					Mask: net.CIDRMask(32, 32),
+				}
+				allowedips = append(allowedips, ipnet)
+			}
+		}
+		// handle egress gateway peers
+		if node.IsEgressGateway == "yes" {
+			hasGateway = true
+			ranges := node.EgressGatewayRanges
+			for _, iprange := range ranges { // go through each cidr for egress gateway
+				_, ipnet, err := net.ParseCIDR(iprange) // confirming it's valid cidr
+				if err != nil {
+					Log("could not parse gateway IP range. Not adding "+iprange, 1)
+					continue // if can't parse CIDR
+				}
+				nodeEndpointArr := strings.Split(node.Endpoint, ":") // getting the public ip of node
+				if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) { // ensuring egress gateway range does not contain public ip of node
+					Log("egress IP range of "+iprange+" overlaps with "+node.Endpoint+", omitting", 2)
+					continue // skip adding egress range if overlaps with node's ip
+				}
+				if ipnet.Contains(net.ParseIP(nodecfg.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
+					Log("egress IP range of "+iprange+" overlaps with "+nodecfg.LocalAddress+", omitting", 2)
+					continue // skip adding egress range if overlaps with node's local ip
+				}
+				gateways = append(gateways, iprange)
+				if err != nil {
+					Log("ERROR ENCOUNTERED SETTING GATEWAY", 1)
+				} else {
+					allowedips = append(allowedips, *ipnet)
+				}
+			}
+		}
+		if node.Address6 != "" && dualstack {
+			var addr6 = net.IPNet{
+				IP:   net.ParseIP(node.Address6),
+				Mask: net.CIDRMask(128, 128),
+			}
+			allowedips = append(allowedips, addr6)
+		}
+		if nodecfg.IsServer == "yes" && !(node.IsServer == "yes") {
+			peer = wgtypes.PeerConfig{
+				PublicKey:                   pubkey,
+				PersistentKeepaliveInterval: &keepaliveserver,
+				ReplaceAllowedIPs:           true,
+				AllowedIPs:                  allowedips,
+			}
+		} else if keepalive != 0 {
+			peer = wgtypes.PeerConfig{
+				PublicKey:                   pubkey,
+				PersistentKeepaliveInterval: &keepalivedur,
+				Endpoint: &net.UDPAddr{
+					IP:   net.ParseIP(node.Endpoint),
+					Port: int(node.ListenPort),
+				},
+				ReplaceAllowedIPs: true,
+				AllowedIPs:        allowedips,
+			}
+		} else {
+			peer = wgtypes.PeerConfig{
+				PublicKey: pubkey,
+				Endpoint: &net.UDPAddr{
+					IP:   net.ParseIP(node.Endpoint),
+					Port: int(node.ListenPort),
+				},
+				ReplaceAllowedIPs: true,
+				AllowedIPs:        allowedips,
+			}
+		}
+		peers = append(peers, peer)
+	}
+	if isIngressGateway {
+		extPeers, err := GetServerExtPeers(macaddress, network, dualstack)
+		if err == nil {
+			peers = append(peers, extPeers...)
+		} else {
+			Log("ERROR RETRIEVING EXTERNAL PEERS ON SERVER", 1)
+		}
+	}
+	return peers, hasGateway, gateways, err
+}
+
+// GetServerExtPeers - gets the extpeers for a client
+func GetServerExtPeers(macaddress string, network string, dualstack bool) ([]wgtypes.PeerConfig, error) {
+	var peers []wgtypes.PeerConfig
+	var nodecfg models.Node
+	var extPeers []models.Node
+	var err error
+	// fill above fields from either client or server
+
+	nodecfg, err = GetNode(macaddress, network)
+	if err != nil {
+		return nil, err
+	}
+	var tempPeers []models.ExtPeersResponse
+	tempPeers, err = GetExtPeersList(nodecfg.MacAddress, nodecfg.Network)
+	if err != nil {
+		return nil, err
+	}
+	for i := 0; i < len(tempPeers); i++ {
+		extPeers = append(extPeers, models.Node{
+			Address:             tempPeers[i].Address,
+			Address6:            tempPeers[i].Address6,
+			Endpoint:            tempPeers[i].Endpoint,
+			PublicKey:           tempPeers[i].PublicKey,
+			PersistentKeepalive: tempPeers[i].KeepAlive,
+			ListenPort:          tempPeers[i].ListenPort,
+			LocalAddress:        tempPeers[i].LocalAddress,
+		})
+	}
+	for _, extPeer := range extPeers {
+		pubkey, err := wgtypes.ParseKey(extPeer.PublicKey)
+		if err != nil {
+			return peers, err
+		}
+
+		if nodecfg.PublicKey == extPeer.PublicKey {
+			continue
+		}
+
+		var peer wgtypes.PeerConfig
+		var peeraddr = net.IPNet{
+			IP:   net.ParseIP(extPeer.Address),
+			Mask: net.CIDRMask(32, 32),
+		}
+		var allowedips []net.IPNet
+		allowedips = append(allowedips, peeraddr)
+
+		if extPeer.Address6 != "" && dualstack {
+			var addr6 = net.IPNet{
+				IP:   net.ParseIP(extPeer.Address6),
+				Mask: net.CIDRMask(128, 128),
+			}
+			allowedips = append(allowedips, addr6)
+		}
+		peer = wgtypes.PeerConfig{
+			PublicKey:         pubkey,
+			ReplaceAllowedIPs: true,
+			AllowedIPs:        allowedips,
+		}
+		peers = append(peers, peer)
+	}
+	return peers, err
+}
+
+// == Private ==
+
+func isDeleteError(err error) bool {
+	return err != nil && strings.Contains(err.Error(), models.NODE_DELETE)
+}
+
+func checkNodeActions(node *models.Node, networkName string, localNode *models.Node) string {
+	if (node.Action == models.NODE_UPDATE_KEY || localNode.Action == models.NODE_UPDATE_KEY) &&
+		node.IsStatic != "yes" {
+		err := setWGKeyConfig(*node)
+		if err != nil {
+			Log("unable to process reset keys request: "+err.Error(), 1)
+			return ""
+		}
+	}
+	if node.Action == models.NODE_DELETE || localNode.Action == models.NODE_DELETE {
+		err := ServerLeave(node.MacAddress, networkName)
+		if err != nil {
+			Log("error deleting locally: "+err.Error(), 1)
+		}
+		return models.NODE_DELETE
+	}
+	return ""
+}

+ 47 - 0
logic/serverconf.go

@@ -0,0 +1,47 @@
+package logic
+
+import (
+	"encoding/json"
+
+	"github.com/gravitl/netmaker/database"
+)
+
+type serverData struct {
+	PrivateKey string `json:"privatekey,omitempty" bson:"privatekey,omitempty"`
+}
+
+// StorePrivKey - stores server client WireGuard privatekey if needed
+func StorePrivKey(serverID string, privateKey string) error {
+	var newData *serverData
+	newData = &serverData{}
+	var err error
+	var data []byte
+	newData.PrivateKey = privateKey
+	data, err = json.Marshal(newData)
+	if err != nil {
+		return err
+	}
+	return database.Insert(serverID, string(data), database.SERVERCONF_TABLE_NAME)
+}
+
+// FetchPrivKey - fetches private key
+func FetchPrivKey(serverID string) (string, error) {
+	var dbData string
+	var err error
+	var fetchedData serverData
+	fetchedData = serverData{}
+	dbData, err = database.FetchRecord(database.SERVERCONF_TABLE_NAME, serverID)
+	if err != nil {
+		return "", err
+	}
+	err = json.Unmarshal([]byte(dbData), &fetchedData)
+	if err != nil {
+		return "", err
+	}
+	return fetchedData.PrivateKey, nil
+}
+
+// RemovePrivKey - removes a private key
+func RemovePrivKey(serverID string) error {
+	return database.DeleteRecord(database.SERVERCONF_TABLE_NAME, serverID)
+}

+ 33 - 4
logic/util.go

@@ -4,6 +4,7 @@ package logic
 import (
 	"encoding/base64"
 	"encoding/json"
+	"log"
 	"strconv"
 	"strings"
 	"time"
@@ -12,6 +13,7 @@ import (
 	"github.com/gravitl/netmaker/dnslogic"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/relay"
 	"github.com/gravitl/netmaker/servercfg"
 	"golang.org/x/crypto/bcrypt"
@@ -62,7 +64,7 @@ func DeleteNode(key string, exterminate bool) error {
 		}
 	} else {
 		if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
-			functions.PrintUserLog("", err.Error(), 2)
+			Log(err.Error(), 2)
 		}
 	}
 	if err := database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
@@ -187,19 +189,19 @@ func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error
 		if database.IsEmptyRecord(err) {
 			return peers, nil
 		}
-		functions.PrintUserLog("", err.Error(), 2)
+		Log(err.Error(), 2)
 		return nil, err
 	}
 	udppeers, errN := database.GetPeers(networkName)
 	if errN != nil {
-		functions.PrintUserLog("", errN.Error(), 2)
+		Log(errN.Error(), 2)
 	}
 	for _, value := range collection {
 		var node models.Node
 		var peer models.Node
 		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
-			functions.PrintUserLog("", err.Error(), 2)
+			Log(err.Error(), 2)
 			continue
 		}
 		if node.IsEgressGateway == "yes" { // handle egress stuff
@@ -292,3 +294,30 @@ func setPeerInfo(node models.Node) models.Node {
 	peer.IsPending = node.IsPending
 	return peer
 }
+
+func Log(message string, loglevel int) {
+	log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
+	if int32(loglevel) <= servercfg.GetVerbose() && servercfg.GetVerbose() != 0 {
+		log.Println("[netmaker] " + message)
+	}
+}
+
+// == Private Methods ==
+
+func setIPForwardingLinux() error {
+	out, err := ncutils.RunCmd("sysctl net.ipv4.ip_forward", true)
+	if err != nil {
+		log.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
+		return err
+	} else {
+		s := strings.Fields(string(out))
+		if s[2] != "1" {
+			_, err = ncutils.RunCmd("sysctl -w net.ipv4.ip_forward=1", true)
+			if err != nil {
+				log.Println("WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
+				return err
+			}
+		}
+	}
+	return nil
+}

+ 289 - 0
logic/wireguard.go

@@ -1,8 +1,20 @@
 package logic
 
 import (
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+	"time"
+
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"golang.zx2c4.com/wireguard/wgctrl"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
 // GetSystemPeers - gets the server peers
@@ -24,3 +36,280 @@ func GetSystemPeers(node *models.Node) (map[string]string, error) {
 	}
 	return peers, nil
 }
+
+// RemoveConf - removes a configuration for a given WireGuard interface
+func RemoveConf(iface string, printlog bool) error {
+	var err error
+	confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
+	err = removeWGQuickConf(confPath, printlog)
+	return err
+}
+
+// == Private Methods ==
+
+func setWGConfig(node models.Node, network string, peerupdate bool) error {
+
+	node.SetID()
+	peers, hasGateway, gateways, err := GetServerPeers(node.MacAddress, node.Network, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
+	if err != nil {
+		return err
+	}
+	privkey, err := FetchPrivKey(node.ID)
+	if err != nil {
+		return err
+	}
+	if peerupdate {
+		var iface string
+		iface = node.Interface
+		err = setServerPeers(iface, node.PersistentKeepalive, peers)
+	} else {
+		err = initWireguard(&node, privkey, peers, hasGateway, gateways)
+	}
+	Log("finished setting wg config on server "+node.Name, 1)
+	return err
+}
+
+func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
+
+	key, err := wgtypes.ParseKey(privkey)
+	if err != nil {
+		return err
+	}
+
+	wgclient, err := wgctrl.New()
+	if err != nil {
+		return err
+	}
+	defer wgclient.Close()
+
+	var ifacename string
+	if node.Interface != "" {
+		ifacename = node.Interface
+	} else {
+		Log("no server interface provided to configure", 2)
+	}
+	if node.Address == "" {
+		Log("no server address to provided configure", 2)
+	}
+
+	if ncutils.IsKernel() {
+		Log("setting kernel device "+ifacename, 2)
+		setKernelDevice(ifacename, node.Address)
+	}
+
+	nodeport := int(node.ListenPort)
+	var conf wgtypes.Config
+	conf = wgtypes.Config{
+		PrivateKey:   &key,
+		ListenPort:   &nodeport,
+		ReplacePeers: true,
+		Peers:        peers,
+	}
+
+	if !ncutils.IsKernel() {
+		var newConf string
+		newConf, _ = ncutils.CreateUserSpaceConf(node.Address, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), node.MTU, node.PersistentKeepalive, peers)
+		confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf"
+		Log("writing wg conf file to: "+confPath, 1)
+		err = ioutil.WriteFile(confPath, []byte(newConf), 0644)
+		if err != nil {
+			Log("error writing wg conf file to "+confPath+": "+err.Error(), 1)
+			return err
+		}
+		// spin up userspace + apply the conf file
+		var deviceiface string
+		deviceiface = ifacename
+		d, _ := wgclient.Device(deviceiface)
+		for d != nil && d.Name == deviceiface {
+			_ = RemoveConf(ifacename, false) // remove interface first
+			time.Sleep(time.Second >> 2)
+			d, _ = wgclient.Device(deviceiface)
+		}
+		time.Sleep(time.Second >> 2)
+		err = applyWGQuickConf(confPath)
+		if err != nil {
+			Log("failed to create wireguard interface", 1)
+			return err
+		}
+	} else {
+		ipExec, err := exec.LookPath("ip")
+		if err != nil {
+			return err
+		}
+
+		_, err = wgclient.Device(ifacename)
+		if err != nil {
+			if os.IsNotExist(err) {
+				fmt.Println("Device does not exist: ")
+				fmt.Println(err)
+			} else {
+				return errors.New("Unknown config error: " + err.Error())
+			}
+		}
+
+		err = wgclient.ConfigureDevice(ifacename, conf)
+		if err != nil {
+			if os.IsNotExist(err) {
+				fmt.Println("Device does not exist: ")
+				fmt.Println(err)
+			} else {
+				fmt.Printf("This is inconvenient: %v", err)
+			}
+		}
+
+		if _, err := ncutils.RunCmd(ipExec+" link set down dev "+ifacename, false); err != nil {
+			Log("attempted to remove interface before editing", 2)
+			return err
+		}
+
+		if node.PostDown != "" {
+			runcmds := strings.Split(node.PostDown, "; ")
+			_ = ncutils.RunCmds(runcmds, true)
+		}
+		// set MTU of node interface
+		if _, err := ncutils.RunCmd(ipExec+" link set mtu "+strconv.Itoa(int(node.MTU))+" up dev "+ifacename, true); err != nil {
+			Log("failed to create interface with mtu "+ifacename, 2)
+			return err
+		}
+
+		if node.PostUp != "" {
+			runcmds := strings.Split(node.PostUp, "; ")
+			_ = ncutils.RunCmds(runcmds, true)
+		}
+		if hasGateway {
+			for _, gateway := range gateways {
+				_, _ = ncutils.RunCmd(ipExec+" -4 route add "+gateway+" dev "+ifacename, true)
+			}
+		}
+		if node.Address6 != "" && node.IsDualStack == "yes" {
+			log.Println("[netclient] adding address: "+node.Address6, 1)
+			_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/64", true)
+		}
+	}
+
+	return err
+}
+
+func setKernelDevice(ifacename string, address string) error {
+	ipExec, err := exec.LookPath("ip")
+	if err != nil {
+		return err
+	}
+
+	_, _ = ncutils.RunCmd("ip link delete dev "+ifacename, false)
+	_, _ = ncutils.RunCmd(ipExec+" link add dev "+ifacename+" type wireguard", true)
+	_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address+"/24", true) // this is a bug waiting to happen
+
+	return nil
+}
+
+func applyWGQuickConf(confPath string) error {
+	if _, err := ncutils.RunCmd("wg-quick up "+confPath, true); err != nil {
+		return err
+	}
+	return nil
+}
+
+func removeWGQuickConf(confPath string, printlog bool) error {
+	if _, err := ncutils.RunCmd("wg-quick down "+confPath, printlog); err != nil {
+		return err
+	}
+	return nil
+}
+
+func setServerPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
+
+	client, err := wgctrl.New()
+	if err != nil {
+		Log("failed to start wgctrl", 0)
+		return err
+	}
+
+	device, err := client.Device(iface)
+	if err != nil {
+		Log("failed to parse interface", 0)
+		return err
+	}
+	devicePeers := device.Peers
+	if len(devicePeers) > 1 && len(peers) == 0 {
+		Log("no peers pulled", 1)
+		return err
+	}
+
+	for _, peer := range peers {
+
+		for _, currentPeer := range devicePeers {
+			if currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
+				currentPeer.PublicKey.String() != peer.PublicKey.String() {
+				_, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
+				if err != nil {
+					log.Println("error removing peer", peer.Endpoint.String())
+				}
+			}
+		}
+		udpendpoint := peer.Endpoint.String()
+		var allowedips string
+		var iparr []string
+		for _, ipaddr := range peer.AllowedIPs {
+			iparr = append(iparr, ipaddr.String())
+		}
+		allowedips = strings.Join(iparr, ",")
+		keepAliveString := strconv.Itoa(int(keepalive))
+		if keepAliveString == "0" {
+			keepAliveString = "5"
+		}
+		if peer.Endpoint != nil {
+			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
+				" endpoint "+udpendpoint+
+				" persistent-keepalive "+keepAliveString+
+				" allowed-ips "+allowedips, true)
+		} else {
+			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
+				" persistent-keepalive "+keepAliveString+
+				" allowed-ips "+allowedips, true)
+		}
+		if err != nil {
+			Log("error setting peer "+peer.PublicKey.String(), 1)
+		}
+	}
+
+	for _, currentPeer := range devicePeers {
+		shouldDelete := true
+		for _, peer := range peers {
+			if peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
+				shouldDelete = false
+			}
+		}
+		if shouldDelete {
+			output, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
+			if err != nil {
+				log.Println(output, "error removing peer", currentPeer.PublicKey.String())
+			}
+		}
+	}
+
+	return nil
+}
+
+func setWGKeyConfig(node models.Node) error {
+
+	node.SetID()
+	privatekey, err := wgtypes.GeneratePrivateKey()
+	if err != nil {
+		return err
+	}
+	privkeystring := privatekey.String()
+	publickey := privatekey.PublicKey()
+
+	node.PublicKey = publickey.String()
+
+	err = StorePrivKey(node.ID, privkeystring)
+	if err != nil {
+		return err
+	}
+	if node.Action == models.NODE_UPDATE_KEY {
+		node.Action = models.NODE_NOOP
+	}
+
+	return setWGConfig(node, node.Network, false)
+}

+ 2 - 1
main.go

@@ -120,7 +120,8 @@ func runClient(wg *sync.WaitGroup) {
 			if err := serverctl.HandleContainedClient(); err != nil {
 				// PASS
 			}
-			time.Sleep(time.Second * 15)
+			var checkintime = time.Duration(servercfg.GetServerCheckinInterval()) * time.Second
+			time.Sleep(checkintime)
 		}
 	}()
 }

+ 6 - 3
netclient/command/commands.go

@@ -25,8 +25,11 @@ var (
 
 func Join(cfg config.ClientConfig, privateKey string) error {
 
-	err := functions.JoinNetwork(cfg, privateKey)
-
+	var err error
+	err = functions.JoinNetwork(cfg, privateKey)
+	if err != nil && cfg.Node.IsServer != "yes" { // make sure server side is cleaned up
+		return err
+	}
 	if err != nil && !cfg.DebugJoin {
 		if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
 			ncutils.PrintLog("error installing: "+err.Error(), 1)
@@ -39,7 +42,7 @@ func Join(cfg config.ClientConfig, privateKey string) error {
 			}
 			if cfg.Daemon != "off" {
 				if ncutils.IsLinux() {
-					err = daemon.RemoveSystemDServices(cfg.Network)
+					err = daemon.RemoveSystemDServices()
 				}
 				if err != nil {
 					ncutils.PrintLog("error removing services: "+err.Error(), 1)

+ 10 - 29
netclient/daemon/systemd.go

@@ -105,30 +105,17 @@ func CleanupLinux() {
 }
 
 // RemoveSystemDServices - removes the systemd services on a machine
-func RemoveSystemDServices(network string) error {
+func RemoveSystemDServices() error {
 	//sysExec, err := exec.LookPath("systemctl")
-	if !ncutils.IsWindows() {
-		fullremove, err := isOnlyService(network)
+	var err error
+	if !ncutils.IsWindows() && isOnlyService() {
 		if err != nil {
 			log.Println(err)
 		}
-
-		if fullremove {
-			_, err = ncutils.RunCmd("systemctl disable netclient.service", true)
-		}
-		_, _ = ncutils.RunCmd("systemctl daemon-reload", true)
-
-		if ncutils.FileExists("/etc/systemd/system/netclient.timer") {
-			_, _ = ncutils.RunCmd("systemctl disable netclient.timer", true)
-		}
-		if fullremove {
-			if ncutils.FileExists("/etc/systemd/system/netclient.service") {
-				err = os.Remove("/etc/systemd/system/netclient.service")
-			}
-		}
-		if ncutils.FileExists("/etc/systemd/system/netclient.timer") {
-			err = os.Remove("/etc/systemd/system/netclient.timer")
-		}
+		_, err = ncutils.RunCmd("systemctl disable netclient.service", true)
+		_, err = ncutils.RunCmd("systemctl disable netclient.timer", true)
+		err = os.Remove("/etc/systemd/system/netclient.service")
+		err = os.Remove("/etc/systemd/system/netclient.timer")
 		if err != nil {
 			log.Println("Error removing file. Please investigate.")
 			log.Println(err)
@@ -139,16 +126,10 @@ func RemoveSystemDServices(network string) error {
 	return nil
 }
 
-func isOnlyService(network string) (bool, error) {
-	isonly := false
+func isOnlyService() bool {
 	files, err := filepath.Glob("/etc/netclient/config/netconfig-*")
 	if err != nil {
-		return isonly, err
+		return false
 	}
-	count := len(files)
-	if count == 0 {
-		isonly = true
-	}
-	return isonly, err
-
+	return len(files) == 0
 }

+ 39 - 50
netclient/functions/checkin.go

@@ -9,7 +9,6 @@ import (
 	"strings"
 
 	nodepb "github.com/gravitl/netmaker/grpc"
-	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
@@ -197,11 +196,6 @@ func Pull(network string, manual bool) (*models.Node, error) {
 		if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
 			return nil, err
 		}
-	} else { // handle server side read
-		resNode, err = logic.GetNode(node.MacAddress, node.Network)
-		if err != nil && !ncutils.IsEmptyRecord(err) {
-			return nil, err
-		}
 	}
 	// ensure that the OS never changes
 	resNode.OS = runtime.GOOS
@@ -259,6 +253,7 @@ func Pull(network string, manual bool) (*models.Node, error) {
 
 // Push - pushes current client configuration to server
 func Push(network string) error {
+
 	cfg, err := config.ReadConfig(network)
 	if err != nil {
 		return err
@@ -268,59 +263,53 @@ func Push(network string) error {
 	postnode.OS = runtime.GOOS
 	postnode.SetLastCheckIn()
 
-	if postnode.IsServer != "yes" { // handle client side
-		var header metadata.MD
-		var wcclient nodepb.NodeServiceClient
-		conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-			ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-		if err != nil {
-			ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
-			return err
-		}
-		defer conn.Close()
-		wcclient = nodepb.NewNodeServiceClient(conn)
-
-		ctx, err := auth.SetJWT(wcclient, network)
-		if err != nil {
-			ncutils.PrintLog("Failed to authenticate with server: "+err.Error(), 1)
-			return err
-		}
-		if postnode.IsPending != "yes" {
-			privateKey, err := wireguard.RetrievePrivKey(network)
-			if err != nil {
-				return err
-			}
-			privateKeyWG, err := wgtypes.ParseKey(privateKey)
-			if err != nil {
-				return err
-			}
-			if postnode.PublicKey != privateKeyWG.PublicKey().String() {
-				postnode.PublicKey = privateKeyWG.PublicKey().String()
-			}
-		}
-		nodeData, err := json.Marshal(&postnode)
-		if err != nil {
-			return err
-		}
+	var header metadata.MD
+	var wcclient nodepb.NodeServiceClient
+	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+	if err != nil {
+		ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
+		return err
+	}
+	defer conn.Close()
+	wcclient = nodepb.NewNodeServiceClient(conn)
 
-		req := &nodepb.Object{
-			Data:     string(nodeData),
-			Type:     nodepb.NODE_TYPE,
-			Metadata: "",
-		}
-		data, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
+	ctx, err := auth.SetJWT(wcclient, network)
+	if err != nil {
+		ncutils.PrintLog("Failed to authenticate with server: "+err.Error(), 1)
+		return err
+	}
+	if postnode.IsPending != "yes" {
+		privateKey, err := wireguard.RetrievePrivKey(network)
 		if err != nil {
 			return err
 		}
-		err = json.Unmarshal([]byte(data.Data), &postnode)
+		privateKeyWG, err := wgtypes.ParseKey(privateKey)
 		if err != nil {
 			return err
 		}
-	} else {
-		if err = postnode.Update(&postnode); err != nil {
-			return err
+		if postnode.PublicKey != privateKeyWG.PublicKey().String() {
+			postnode.PublicKey = privateKeyWG.PublicKey().String()
 		}
 	}
+	nodeData, err := json.Marshal(&postnode)
+	if err != nil {
+		return err
+	}
+
+	req := &nodepb.Object{
+		Data:     string(nodeData),
+		Type:     nodepb.NODE_TYPE,
+		Metadata: "",
+	}
+	data, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal([]byte(data.Data), &postnode)
+	if err != nil {
+		return err
+	}
 	err = config.ModConfig(&postnode)
 	return err
 }

+ 1 - 1
netclient/functions/common.go

@@ -231,7 +231,7 @@ func RemoveLocalInstance(cfg *config.ClientConfig, networkName string) error {
 		} else if ncutils.IsMac() {
 			//TODO: Delete mac daemon
 		} else {
-			err = daemon.RemoveSystemDServices(networkName)
+			err = daemon.RemoveSystemDServices()
 		}
 	}
 	return err

+ 36 - 51
netclient/functions/join.go

@@ -8,7 +8,6 @@ import (
 	"log"
 
 	nodepb "github.com/gravitl/netmaker/grpc"
-	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
@@ -24,29 +23,30 @@ import (
 // JoinNetwork - helps a client join a network
 func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 
-	hasnet := local.HasNetwork(cfg.Network)
-	if hasnet {
-		err := errors.New("ALREADY_INSTALLED. Netclient appears to already be installed for " + cfg.Network + ". To re-install, please remove by executing 'sudo netclient leave -n " + cfg.Network + "'. Then re-run the install command.")
-		return err
-	}
-
-	err := config.Write(&cfg, cfg.Network)
-	if err != nil {
-		return err
-	}
-
 	if cfg.Node.Network == "" {
 		return errors.New("no network provided")
 	}
 
+	var err error
+	if cfg.Node.IsServer != "yes" {
+		if local.HasNetwork(cfg.Network) {
+			err := errors.New("ALREADY_INSTALLED. Netclient appears to already be installed for " + cfg.Network + ". To re-install, please remove by executing 'sudo netclient leave -n " + cfg.Network + "'. Then re-run the install command.")
+			return err
+		}
+		err = config.Write(&cfg, cfg.Network)
+		if err != nil {
+			return err
+		}
+		if cfg.Node.Password == "" {
+			cfg.Node.Password = ncutils.GenPass()
+		}
+		auth.StoreSecret(cfg.Node.Password, cfg.Node.Network)
+	}
+
 	if cfg.Node.LocalRange != "" && cfg.Node.LocalAddress == "" {
 		log.Println("local vpn, getting local address from range: " + cfg.Node.LocalRange)
 		cfg.Node.LocalAddress = getLocalIP(cfg.Node)
 	}
-	if cfg.Node.Password == "" {
-		cfg.Node.Password = ncutils.GenPass()
-	}
-	auth.StoreSecret(cfg.Node.Password, cfg.Node.Network)
 
 	// set endpoint if blank. set to local if local net, retrieve from function if not
 	if cfg.Node.Endpoint == "" {
@@ -140,19 +140,6 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 		if err = json.Unmarshal([]byte(nodeData), &node); err != nil {
 			return err
 		}
-	} else { // handle server side node creation
-		ncutils.Log("adding a server instance on network " + postnode.Network)
-		if err = config.ModConfig(postnode); err != nil {
-			return err
-		}
-		node, err = logic.CreateNode(*postnode, cfg.Network)
-		if err != nil {
-			return err
-		}
-		err = logic.SetNetworkNodesLastModified(node.Network)
-		if err != nil {
-			return err
-		}
 	}
 
 	// get free port based on returned default listen port
@@ -169,28 +156,26 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 		}
 		node.Endpoint = node.LocalAddress
 	}
-
-	err = config.ModConfig(&node)
-	if err != nil {
-		return err
-	}
-
-	err = wireguard.StorePrivKey(privateKey, cfg.Network)
-	if err != nil {
-		return err
-	}
-
-	// pushing any local changes to server before starting wireguard
-	err = Push(cfg.Network)
-	if err != nil {
-		return err
-	}
-
-	if node.IsPending == "yes" {
-		ncutils.Log("Node is marked as PENDING.")
-		ncutils.Log("Awaiting approval from Admin before configuring WireGuard.")
-		if cfg.Daemon != "off" {
-			return daemon.InstallDaemon(cfg)
+	if node.IsServer != "yes" { // == handle client side ==
+		err = config.ModConfig(&node)
+		if err != nil {
+			return err
+		}
+		err = wireguard.StorePrivKey(privateKey, cfg.Network)
+		if err != nil {
+			return err
+		}
+		if node.IsPending == "yes" {
+			ncutils.Log("Node is marked as PENDING.")
+			ncutils.Log("Awaiting approval from Admin before configuring WireGuard.")
+			if cfg.Daemon != "off" {
+				return daemon.InstallDaemon(cfg)
+			}
+		}
+		// pushing any local changes to server before starting wireguard
+		err = Push(cfg.Network)
+		if err != nil {
+			return err
 		}
 	}
 

+ 6 - 1
netclient/main.go

@@ -24,7 +24,12 @@ func main() {
 	app := cli.NewApp()
 	app.Name = "Netclient CLI"
 	app.Usage = "Netmaker's netclient agent and CLI. Used to perform interactions with Netmaker server and set local WireGuard config."
-	app.Version = "v0.8.3"
+	app.Version = "v0.8.4"
+
+	hostname, err := os.Hostname()
+	if err != nil {
+		hostname = ""
+	}
 
 	hostname, err := os.Hostname()
 	if err != nil {

+ 7 - 2
netclient/ncutils/netclientutils.go

@@ -155,7 +155,12 @@ func parsePeers(keepalive int32, peers []wgtypes.PeerConfig) (string, error) {
 	if keepalive <= 0 {
 		keepalive = 20
 	}
+	
 	for _, peer := range peers {
+		endpointString :=  ""
+		if peer.Endpoint != nil && peer.Endpoint.String() != "" {
+			endpointString += "Endpoint = " + peer.Endpoint.String()
+		}
 		newAllowedIps := []string{}
 		for _, allowedIP := range peer.AllowedIPs {
 			newAllowedIps = append(newAllowedIps, allowedIP.String())
@@ -163,14 +168,14 @@ func parsePeers(keepalive int32, peers []wgtypes.PeerConfig) (string, error) {
 		peersString += fmt.Sprintf(`[Peer]
 PublicKey = %s
 AllowedIps = %s
-Endpoint = %s
 PersistentKeepAlive = %s
+%s
 
 `,
 			peer.PublicKey.String(),
 			strings.Join(newAllowedIps, ","),
-			peer.Endpoint.String(),
 			strconv.Itoa(int(keepalive)),
+			endpointString,
 		)
 	}
 	return peersString, nil

+ 27 - 90
netclient/server/grpc.go

@@ -9,7 +9,6 @@ import (
 	"time"
 
 	nodepb "github.com/gravitl/netmaker/grpc"
-	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
@@ -73,73 +72,21 @@ func CheckIn(network string) (*models.Node, error) {
 	return &node, err
 }
 
-/*
-func RemoveNetwork(network string) error {
-	//need to  implement checkin on server side
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return err
-	}
-	servercfg := cfg.Server
-	node := cfg.Node
-	log.Println("Deleting remote node with MAC: " + node.MacAddress)
-
-	var wcclient nodepb.NodeServiceClient
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-	if err != nil {
-		log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
-		//return err
-	} else {
-		wcclient = nodepb.NewNodeServiceClient(conn)
-		ctx, err := auth.SetJWT(wcclient, network)
-		if err != nil {
-			//return err
-			log.Printf("Failed to authenticate: %v", err)
-		} else {
-
-			var header metadata.MD
-
-			_, err = wcclient.DeleteNode(
-				ctx,
-				&nodepb.Object{
-					Data: node.MacAddress + "###" + node.Network,
-					Type: nodepb.STRING_TYPE,
-				},
-				grpc.Header(&header),
-			)
-			if err != nil {
-				log.Printf("Encountered error deleting node: %v", err)
-				log.Println(err)
-			} else {
-				log.Println("Deleted node " + node.MacAddress)
-			}
-		}
-	}
-	//err = functions.RemoveLocalInstance(network)
-
-	return err
-}
-*/
-
 // GetPeers - gets the peers for a node
 func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool, isServer bool) ([]wgtypes.PeerConfig, bool, []string, error) {
 	hasGateway := false
+	var err error
 	var gateways []string
 	var peers []wgtypes.PeerConfig
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
-	}
-	nodecfg := cfg.Node
-	keepalive := nodecfg.PersistentKeepalive
-	keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
-	keepaliveserver, err := time.ParseDuration(strconv.FormatInt(int64(5), 10) + "s")
-	if err != nil {
-		log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
-	}
-	var nodes []models.Node // fill this either from server or client
-	if !isServer {          // set peers client side
+	var nodecfg models.Node
+	var nodes []models.Node // fill above fields from server or client
+
+	if !isServer { // set peers client side
+		cfg, err := config.ReadConfig(network)
+		if err != nil {
+			log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
+		}
+		nodecfg = cfg.Node
 		var wcclient nodepb.NodeServiceClient
 		conn, err := grpc.Dial(cfg.Server.GRPCAddress,
 			ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
@@ -173,11 +120,13 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
 			log.Println("Error unmarshaling data for peers")
 			return nil, hasGateway, gateways, err
 		}
-	} else { // set peers serverside
-		nodes, err = logic.GetPeers(nodecfg)
-		if err != nil {
-			return nil, hasGateway, gateways, err
-		}
+	}
+
+	keepalive := nodecfg.PersistentKeepalive
+	keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
+	keepaliveserver, err := time.ParseDuration(strconv.FormatInt(int64(5), 10) + "s")
+	if err != nil {
+		log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
 	}
 
 	for _, node := range nodes {
@@ -299,14 +248,18 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
 // GetExtPeers - gets the extpeers for a client
 func GetExtPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, error) {
 	var peers []wgtypes.PeerConfig
-
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
-	}
-	nodecfg := cfg.Node
+	var nodecfg models.Node
 	var extPeers []models.Node
+	var err error
+	// fill above fields from either client or server
+
 	if nodecfg.IsServer != "yes" { // fill extPeers with client side logic
+		var cfg *config.ClientConfig
+		cfg, err = config.ReadConfig(network)
+		if err != nil {
+			log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
+		}
+		nodecfg = cfg.Node
 		var wcclient nodepb.NodeServiceClient
 
 		conn, err := grpc.Dial(cfg.Server.GRPCAddress,
@@ -339,22 +292,6 @@ func GetExtPeers(macaddress string, network string, server string, dualstack boo
 		if err = json.Unmarshal([]byte(responseObject.Data), &extPeers); err != nil {
 			return nil, err
 		}
-	} else { // fill extPeers with server side logic
-		tempPeers, err := logic.GetExtPeersList(nodecfg.MacAddress, nodecfg.Network)
-		if err != nil {
-			return nil, err
-		}
-		for i := 0; i < len(tempPeers); i++ {
-			extPeers = append(extPeers, models.Node{
-				Address:             tempPeers[i].Address,
-				Address6:            tempPeers[i].Address6,
-				Endpoint:            tempPeers[i].Endpoint,
-				PublicKey:           tempPeers[i].PublicKey,
-				PersistentKeepalive: tempPeers[i].KeepAlive,
-				ListenPort:          tempPeers[i].ListenPort,
-				LocalAddress:        tempPeers[i].LocalAddress,
-			})
-		}
 	}
 	for _, extPeer := range extPeers {
 		pubkey, err := wgtypes.ParseKey(extPeer.PublicKey)

+ 2 - 1
netclient/wireguard/unix.go

@@ -66,8 +66,9 @@ func RemoveWGQuickConf(confPath string, printlog bool) error {
 
 // StorePrivKey - stores wg priv key on disk locally
 func StorePrivKey(key string, network string) error {
+	var err error
 	d1 := []byte(key)
-	err := ioutil.WriteFile(ncutils.GetNetclientPathSpecific()+"wgkey-"+network, d1, 0644)
+	err = ioutil.WriteFile(ncutils.GetNetclientPathSpecific()+"wgkey-"+network, d1, 0644)
 	return err
 }
 

+ 6 - 0
scripts/userspace-entrypoint.sh

@@ -0,0 +1,6 @@
+# If running userspace wireguard in Docker, create missing tun device.
+if [ ! -d /dev/net ]; then mkdir /dev/net; fi
+if [ ! -e /dev/net/tun ]; then  mknod /dev/net/tun c 10 200; fi
+
+# Wait and then run netmaker.
+/bin/sh -c "sleep 3; ./netmaker"

+ 16 - 3
servercfg/serverconf.go

@@ -3,10 +3,11 @@ package servercfg
 import (
 	"errors"
 	"io/ioutil"
-	"net/http"
 	"net"
+	"net/http"
 	"os"
 	"strconv"
+
 	"github.com/gravitl/netmaker/config"
 )
 
@@ -33,6 +34,7 @@ func GetServerConfig() config.ServerConfig {
 	cfg.Verbosity = GetVerbose()
 	cfg.NodeID = GetNodeID()
 	cfg.CheckinInterval = GetCheckinInterval()
+	cfg.ServerCheckinInterval = GetServerCheckinInterval()
 	if IsRestBackend() {
 		cfg.RestBackend = "on"
 	}
@@ -75,7 +77,7 @@ func GetAPIConnString() string {
 	return conn
 }
 func GetVersion() string {
-	version := "0.8.3"
+	version := "0.8.4"
 	if config.Config.Server.Version != "" {
 		version = config.Config.Server.Version
 	}
@@ -385,6 +387,17 @@ func GetNodeID() string {
 	return id
 }
 
+func GetServerCheckinInterval() int64 {
+	var t = int64(5)
+	var envt, _ = strconv.Atoi(os.Getenv("SERVER_CHECKIN_INTERVAL"))
+	if envt > 0 {
+		t = int64(envt)
+	} else if config.Config.Server.ServerCheckinInterval > 0 {
+		t = config.Config.Server.ServerCheckinInterval
+	}
+	return t
+}
+
 // GetMacAddr - get's mac address
 func getMacAddr() string {
 	ifas, err := net.Interfaces()
@@ -399,4 +412,4 @@ func getMacAddr() string {
 		}
 	}
 	return as[0]
-}
+}

+ 21 - 51
serverctl/serverctl.go

@@ -6,11 +6,11 @@ import (
 	"io"
 	"log"
 	"os"
+	"strings"
 
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
-	nccommand "github.com/gravitl/netmaker/netclient/command"
-	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 )
@@ -31,30 +31,6 @@ func GetServerWGConf() (models.IntClient, error) {
 	return models.IntClient{}, errors.New("could not find comms server")
 }
 
-// InstallNetclient netclient installation for server - depricated
-func InstallNetclient() error {
-
-	netclientPath := ncutils.GetNetclientPath()
-	if ncutils.IsWindows() {
-		netclientPath += "\\"
-	} else {
-		netclientPath += "/"
-	}
-	if !FileExists(netclientPath + "netclient") {
-		var err error
-		if ncutils.IsWindows() {
-			_, err = copy(".\\netclient\\netclient", netclientPath+"netclient")
-		} else {
-			_, err = copy("./netclient/netclient", netclientPath+"netclient")
-		}
-		if err != nil {
-			log.Println("could not create " + netclientPath + "netclient")
-			return err
-		}
-	}
-	return nil
-}
-
 // FileExists - checks if local file exists
 func FileExists(f string) bool {
 	info, err := os.Stat(f)
@@ -88,14 +64,14 @@ func copy(src, dst string) (int64, error) {
 	nBytes, err := io.Copy(destination, source)
 	err = os.Chmod(dst, 0755)
 	if err != nil {
-		log.Println(err)
+		logic.Log(err.Error(), 1)
 	}
 	return nBytes, err
 }
 
 // RemoveNetwork - removes a network locally on server
 func RemoveNetwork(network string) (bool, error) {
-	err := nccommand.Leave(config.ClientConfig{Network: network})
+	err := logic.ServerLeave(servercfg.GetNodeID(), network)
 	return true, err
 }
 
@@ -106,7 +82,7 @@ func InitServerNetclient() error {
 	if os.IsNotExist(err) {
 		os.MkdirAll(netclientDir+"/config", 744)
 	} else if err != nil {
-		log.Println("[netmaker] could not find or create", netclientDir)
+		logic.Log("[netmaker] could not find or create "+netclientDir, 1)
 		return err
 	}
 	return nil
@@ -124,16 +100,16 @@ func HandleContainedClient() error {
 		}
 		log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
 		err := SyncNetworks(servernets)
-		if err != nil && servercfg.GetVerbose() >= 1 {
-			log.Printf("[netmaker] error syncing networks %s \n", err)
-		}
-		err = nccommand.CheckIn(config.ClientConfig{Network: "all"})
-		if err != nil && servercfg.GetVerbose() >= 1 {
-			log.Printf("[netmaker] error occurred %s \n", err)
+		if err != nil {
+			logic.Log("error syncing networks: "+err.Error(), 1)
 		}
-		if servercfg.GetVerbose() >= 3 {
-			log.Println("[netmaker]", "completed a checkin call")
+		for _, serverNet := range servernets {
+			err = logic.ServerCheckin(servercfg.GetNodeID(), serverNet.NetID)
+			if err != nil {
+				logic.Log("error occurred during server checkin: "+err.Error(), 1)
+			}
 		}
+		logic.Log("completed a checkin call", 3)
 	}
 	return nil
 }
@@ -160,7 +136,9 @@ func SyncNetworks(servernets []models.Network) error {
 					err = errors.New("network add failed for " + servernet.NetID)
 				}
 				if servercfg.GetVerbose() >= 1 {
-					log.Printf("[netmaker] error adding network %s during sync %s \n", servernet.NetID, err)
+					if !strings.Contains(err.Error(), "macaddress_unique") { // ignore macaddress unique error throws
+						log.Printf("[netmaker] error adding network %s during sync %s \n", servernet.NetID, err)
+					}
 				}
 			}
 		}
@@ -179,7 +157,9 @@ func SyncNetworks(servernets []models.Network) error {
 				if err == nil {
 					err = errors.New("network delete failed for " + localnet)
 				}
-				log.Printf("[netmaker] error removing network %s during sync %s \n", localnet, err)
+				if servercfg.GetVerbose() >= 1 {
+					log.Printf("[netmaker] error removing network %s during sync %s \n", localnet, err)
+				}
 			}
 		}
 	}
@@ -188,17 +168,7 @@ func SyncNetworks(servernets []models.Network) error {
 
 // AddNetwork - add a network to server in client mode
 func AddNetwork(network string) (bool, error) {
-	err := nccommand.Join(config.ClientConfig{
-		Network: network,
-		Daemon:  "off",
-		Node: models.Node{
-			Network:  network,
-			IsServer: "yes",
-			DNSOn:    "no",
-			Name:     models.NODE_SERVER_NAME,
-			MacAddress:     servercfg.GetNodeID(),
-		},
-	}, "")
-	log.Println("[netmaker] Server added to network " + network)
+	err := logic.ServerJoin(network, servercfg.GetNodeID(), "")
+	logic.Log("server added to network "+network, 2)
 	return true, err
 }

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