diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..899687444d37245ae32d7d99ff4ea71e42a95c0f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,68 @@
+BINDIR      := $(CURDIR)/bin
+INSTALL_PATH ?= /usr/local/bin
+DIST_DIRS   := find * -type d -exec
+TARGETS     := darwin/amd64 darwin/arm64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le linux/s390x windows/amd64
+TARGET_OBJS ?= darwin-amd64.tar.gz darwin-amd64.tar.gz.sha256 darwin-amd64.tar.gz.sha256sum darwin-arm64.tar.gz darwin-arm64.tar.gz.sha256 darwin-arm64.tar.gz.sha256sum linux-amd64.tar.gz linux-amd64.tar.gz.sha256 linux-amd64.tar.gz.sha256sum linux-386.tar.gz linux-386.tar.gz.sha256 linux-386.tar.gz.sha256sum linux-arm.tar.gz linux-arm.tar.gz.sha256 linux-arm.tar.gz.sha256sum linux-arm64.tar.gz linux-arm64.tar.gz.sha256 linux-arm64.tar.gz.sha256sum linux-ppc64le.tar.gz linux-ppc64le.tar.gz.sha256 linux-ppc64le.tar.gz.sha256sum linux-s390x.tar.gz linux-s390x.tar.gz.sha256 linux-s390x.tar.gz.sha256sum windows-amd64.zip windows-amd64.zip.sha256 windows-amd64.zip.sha256sum
+BINNAME     ?= rdpgw
+
+# Rebuild the binary if any of these files change
+SRC := $(shell find . -type f -name '*.go' -print) go.mod go.sum
+
+# Required for globs to work correctly
+SHELL      = /usr/bin/env bash
+
+GIT_COMMIT = $(shell git rev-parse HEAD)
+GIT_SHA    = $(shell git rev-parse --short HEAD)
+GIT_TAG    = $(shell git describe --tags --abbrev=0 --exact-match 2>/dev/null)
+GIT_DIRTY  = $(shell test -n "`git status --porcelain`" && echo "dirty" || echo "clean")
+
+ifdef VERSION
+	BINARY_VERSION = $(VERSION)
+endif
+BINARY_VERSION ?= ${GIT_TAG}
+
+VERSION_METADATA = unreleased
+# Clear the "unreleased" string in BuildMetadata
+ifneq ($(GIT_TAG),)
+	VERSION_METADATA =
+endif
+
+.PHONY: all
+all: mod build
+
+# ------------------------------------------------------------------------------
+#  build
+
+.PHONY: build
+build: $(BINDIR)/$(BINNAME)
+
+$(BINDIR)/$(BINNAME): $(SRC)
+	GOMODULE=on go build $(GOFLAGS) -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o '$(BINDIR)'/$(BINNAME) ./cmd/rdpgw
+
+# ------------------------------------------------------------------------------
+#  install
+
+.PHONY: install
+install: build
+	@install "$(BINDIR)/$(BINNAME)" "$(INSTALL_PATH)/$(BINNAME)"
+
+# ------------------------------------------------------------------------------
+#  mod
+
+.PHONY: mod
+mod:
+	go mod tidy
+
+# ------------------------------------------------------------------------------
+#  clean
+
+.PHONY: clean
+clean:
+	@rm -rf '$(BINDIR)' ./_dist
+
+.PHONY: info
+info:
+	 @echo "Version:           ${VERSION}"
+	 @echo "Git Tag:           ${GIT_TAG}"
+	 @echo "Git Commit:        ${GIT_COMMIT}"
+	 @echo "Git Tree State:    ${GIT_DIRTY}"
diff --git a/api/token.go b/cmd/rdpgw/api/token.go
similarity index 94%
rename from api/token.go
rename to cmd/rdpgw/api/token.go
index 07b90c09eef246ff48cac5ead9c60056b5641fd1..328b23328cd7b5557bf87f6214270af0d16a3767 100644
--- a/api/token.go
+++ b/cmd/rdpgw/api/token.go
@@ -4,7 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"github.com/bolkedebruin/rdpgw/security"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/security"
 	"log"
 	"net/http"
 )
diff --git a/api/web.go b/cmd/rdpgw/api/web.go
similarity index 100%
rename from api/web.go
rename to cmd/rdpgw/api/web.go
diff --git a/common/remote.go b/cmd/rdpgw/common/remote.go
similarity index 100%
rename from common/remote.go
rename to cmd/rdpgw/common/remote.go
diff --git a/config/configuration.go b/cmd/rdpgw/config/configuration.go
similarity index 100%
rename from config/configuration.go
rename to cmd/rdpgw/config/configuration.go
diff --git a/main.go b/cmd/rdpgw/main.go
similarity index 89%
rename from main.go
rename to cmd/rdpgw/main.go
index efc115fd5fa1b776d74e3cc2dea78956b322311e..b7beda3169eb0f0673a2fb7f7199fde9f9d647f9 100644
--- a/main.go
+++ b/cmd/rdpgw/main.go
@@ -3,11 +3,11 @@ package main
 import (
 	"context"
 	"crypto/tls"
-	"github.com/bolkedebruin/rdpgw/api"
-	"github.com/bolkedebruin/rdpgw/common"
-	"github.com/bolkedebruin/rdpgw/config"
-	"github.com/bolkedebruin/rdpgw/protocol"
-	"github.com/bolkedebruin/rdpgw/security"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/api"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/common"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/config"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/protocol"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/security"
 	"github.com/coreos/go-oidc/v3/oidc"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
 	"github.com/spf13/cobra"
@@ -68,7 +68,7 @@ func main() {
 		OIDCTokenVerifier:    verifier,
 		PAATokenGenerator:    security.GeneratePAAToken,
 		UserTokenGenerator:   security.GenerateUserToken,
-		EnableUserToken:	  conf.Security.EnableUserToken,
+		EnableUserToken:      conf.Security.EnableUserToken,
 		SessionKey:           []byte(conf.Server.SessionKey),
 		SessionEncryptionKey: []byte(conf.Server.SessionEncryptionKey),
 		Hosts:                conf.Server.Hosts,
@@ -77,7 +77,7 @@ func main() {
 		BandwidthAutoDetect:  conf.Client.BandwidthAutoDetect,
 		ConnectionType:       conf.Client.ConnectionType,
 		SplitUserDomain:      conf.Client.SplitUserDomain,
-		DefaultDomain:		  conf.Client.DefaultDomain,
+		DefaultDomain:        conf.Client.DefaultDomain,
 	}
 	api.NewApi()
 
@@ -127,9 +127,9 @@ func main() {
 			EnableAll: conf.Caps.RedirectAll,
 		},
 		VerifyTunnelCreate: security.VerifyPAAToken,
-		VerifyServerFunc: security.VerifyServerFunc,
-		SendBuf: conf.Server.SendBuf,
-		ReceiveBuf: conf.Server.ReceiveBuf,
+		VerifyServerFunc:   security.VerifyServerFunc,
+		SendBuf:            conf.Server.SendBuf,
+		ReceiveBuf:         conf.Server.ReceiveBuf,
 	}
 	gw := protocol.Gateway{
 		ServerConf: &handlerConfig,
diff --git a/protocol/client.go b/cmd/rdpgw/protocol/client.go
similarity index 100%
rename from protocol/client.go
rename to cmd/rdpgw/protocol/client.go
diff --git a/protocol/common.go b/cmd/rdpgw/protocol/common.go
similarity index 96%
rename from protocol/common.go
rename to cmd/rdpgw/protocol/common.go
index 405445dddb9fdc382255ff611a8e3cf19d2afaaf..ad7c9b0854e73fecf038eb83f4b88d0efc6dd6f5 100644
--- a/protocol/common.go
+++ b/cmd/rdpgw/protocol/common.go
@@ -4,7 +4,7 @@ import (
 	"bytes"
 	"encoding/binary"
 	"errors"
-	"github.com/bolkedebruin/rdpgw/transport"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/transport"
 	"io"
 	"log"
 	"net"
@@ -27,10 +27,10 @@ type SessionInfo struct {
 	ConnId           string
 	// The underlying incoming transport being either websocket or legacy http
 	// in case of websocket TransportOut will equal TransportIn
-	TransportIn      transport.Transport
+	TransportIn transport.Transport
 	// The underlying outgoing transport being either websocket or legacy http
 	// in case of websocket TransportOut will equal TransportOut
-	TransportOut     transport.Transport
+	TransportOut transport.Transport
 	// The remote desktop server (rdp, vnc etc) the clients intends to connect to
 	RemoteServer	 string
 	// The obtained client ip address
diff --git a/protocol/gateway.go b/cmd/rdpgw/protocol/gateway.go
similarity index 98%
rename from protocol/gateway.go
rename to cmd/rdpgw/protocol/gateway.go
index ba864317415f5a53f1b8a5c4940f7a5c3e1c70be..7f95857a9a9454f5f46abddb048c28caf74c1986 100644
--- a/protocol/gateway.go
+++ b/cmd/rdpgw/protocol/gateway.go
@@ -3,8 +3,8 @@ package protocol
 import (
 	"context"
 	"errors"
-	"github.com/bolkedebruin/rdpgw/common"
-	"github.com/bolkedebruin/rdpgw/transport"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/common"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/transport"
 	"github.com/gorilla/websocket"
 	"github.com/patrickmn/go-cache"
 	"github.com/prometheus/client_golang/prometheus"
diff --git a/protocol/protocol_test.go b/cmd/rdpgw/protocol/protocol_test.go
similarity index 100%
rename from protocol/protocol_test.go
rename to cmd/rdpgw/protocol/protocol_test.go
diff --git a/protocol/server.go b/cmd/rdpgw/protocol/server.go
similarity index 98%
rename from protocol/server.go
rename to cmd/rdpgw/protocol/server.go
index cf87132c2a8d4ba67cdc3a507428454c57dd8fc4..4f9c1197ef36cb45a9c85ab396e35c1e77b30116 100644
--- a/protocol/server.go
+++ b/cmd/rdpgw/protocol/server.go
@@ -5,7 +5,7 @@ import (
 	"context"
 	"encoding/binary"
 	"errors"
-	"github.com/bolkedebruin/rdpgw/common"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/common"
 	"io"
 	"log"
 	"net"
@@ -39,13 +39,13 @@ type ServerConf struct {
 	IdleTimeout          int
 	SmartCardAuth        bool
 	TokenAuth            bool
-	ReceiveBuf			 int
-	SendBuf				 int
+	ReceiveBuf           int
+	SendBuf              int
 }
 
 func NewServer(s *SessionInfo, conf *ServerConf) *Server {
 	h := &Server{
-		State:				  SERVER_STATE_INITIAL,
+		State:                SERVER_STATE_INITIAL,
 		Session:              s,
 		RedirectFlags:        makeRedirectFlags(conf.RedirectFlags),
 		IdleTimeout:          conf.IdleTimeout,
diff --git a/protocol/types.go b/cmd/rdpgw/protocol/types.go
similarity index 100%
rename from protocol/types.go
rename to cmd/rdpgw/protocol/types.go
diff --git a/protocol/utf16.go b/cmd/rdpgw/protocol/utf16.go
similarity index 100%
rename from protocol/utf16.go
rename to cmd/rdpgw/protocol/utf16.go
diff --git a/security/jwt.go b/cmd/rdpgw/security/jwt.go
similarity index 98%
rename from security/jwt.go
rename to cmd/rdpgw/security/jwt.go
index 6cae11498d05d905b5e2db894ff60ac8e23f630d..cfc37fda4da9f1fac88d537a23ca07eba35a5b67 100644
--- a/security/jwt.go
+++ b/cmd/rdpgw/security/jwt.go
@@ -4,8 +4,8 @@ import (
 	"context"
 	"errors"
 	"fmt"
-	"github.com/bolkedebruin/rdpgw/common"
-	"github.com/bolkedebruin/rdpgw/protocol"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/common"
+	"github.com/bolkedebruin/rdpgw/cmd/rdpgw/protocol"
 	"github.com/coreos/go-oidc/v3/oidc"
 	"github.com/square/go-jose/v3"
 	"github.com/square/go-jose/v3/jwt"
diff --git a/transport/legacy.go b/cmd/rdpgw/transport/legacy.go
similarity index 100%
rename from transport/legacy.go
rename to cmd/rdpgw/transport/legacy.go
diff --git a/transport/transport.go b/cmd/rdpgw/transport/transport.go
similarity index 100%
rename from transport/transport.go
rename to cmd/rdpgw/transport/transport.go
diff --git a/transport/websocket.go b/cmd/rdpgw/transport/websocket.go
similarity index 100%
rename from transport/websocket.go
rename to cmd/rdpgw/transport/websocket.go