From abc8a0e8fb1a45f0635fe6106e6a6d30b9a34153 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 18 Sep 2024 12:45:01 +0200 Subject: [PATCH 1/5] support unix socket --- main.go | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/main.go b/main.go index d14d6a2..7626297 100644 --- a/main.go +++ b/main.go @@ -42,6 +42,7 @@ type Config struct { UseHostHeader bool `env:"USE_HOST_HEADER" envDefault:"false"` LogTraffic bool `env:"LOG_TRAFFIC" envDefault:"false"` LogConnInfo bool `env:"LOG_CONN_INFO" envDefault:"true"` + UnixSocketPath string `env:"UNIX_SOCKET_PATH" envDefault:""` } var upgrader = websocket.Upgrader{ @@ -81,7 +82,11 @@ func NewProxyHandler(config *Config) (*ProxyHandler, error) { }, nil } -func (h *ProxyHandler) ExtractProxyDest(r *http.Request) (string, error) { +func (h *ProxyHandler) ExtractProxyDest(r *http.Request) (string, string, error) { + if h.cfg.UnixSocketPath != "" { + return "unix", h.cfg.UnixSocketPath, nil + } + addressArg := r.URL.Query().Get("address") hostHeader := r.Host @@ -106,10 +111,10 @@ func (h *ProxyHandler) ExtractProxyDest(r *http.Request) (string, error) { } if !allowed { - return "", fmt.Errorf("proxying to specified address not allowed") + return "", "", fmt.Errorf("proxying to specified address not allowed") } - return addr, nil + return "tcp", addr, nil } func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -117,7 +122,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { log.Printf("Got request from %s", r.RemoteAddr) } - addr, err := h.ExtractProxyDest(r) + network, addr, err := h.ExtractProxyDest(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -130,27 +135,26 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } defer conn.Close() - err = h.HandleWS(conn, addr) + err = h.HandleWS(conn, network, addr) if err != nil { log.Printf("failed to handle websocket: %v\n", err) return } } -func (h *ProxyHandler) HandleWS(conn *websocket.Conn, addr string) error { +func (h *ProxyHandler) HandleWS(conn *websocket.Conn, network, addr string) error { connectionsProcessed.Inc() activeConnections.Inc() defer activeConnections.Dec() - socket, err := net.Dial("tcp", addr) + socket, err := net.Dial(network, addr) if err != nil { return err } defer socket.Close() go func() { - message := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "TCP connection is closed") - // Close the websocket connection when TCP connection loop is finished. + message := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "Connection is closed") defer func() { err := conn.WriteControl(websocket.CloseMessage, message, time.Now().Add(time.Second)) if err != nil { @@ -163,11 +167,13 @@ func (h *ProxyHandler) HandleWS(conn *websocket.Conn, addr string) error { for { n, err := socket.Read(buf) if err != nil { - log.Printf("failed to read from socket: %v\n", err) + if err != io.EOF { + log.Printf("failed to read from socket: %v\n", err) + } return } - proxiedBytes.WithLabelValues("tcp").Add(float64(n)) + proxiedBytes.WithLabelValues(network).Add(float64(n)) if h.cfg.LogTraffic { log.Printf("Got %d bytes pg->client: %s\n", n, base64.StdEncoding.EncodeToString(buf[:n])) @@ -184,7 +190,10 @@ func (h *ProxyHandler) HandleWS(conn *websocket.Conn, addr string) error { for { _, b, err := conn.ReadMessage() if err != nil { - return err + if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { + log.Printf("websocket error: %v", err) + } + return nil } proxiedBytes.WithLabelValues("ws").Add(float64(len(b))) @@ -232,7 +241,9 @@ func main() { log.Fatalf("Failed to parse config: %v", err) } - if cfg.AllowAddrRegex == "" { + if cfg.UnixSocketPath != "" { + log.Printf("Using Unix socket path: %s", cfg.UnixSocketPath) + } else if cfg.AllowAddrRegex == "" { log.Printf("WARN: No regex for allowed addresses, allowing all") } else { log.Printf("Using regex for allowed addresses: %v", cfg.AllowAddrRegex) From f754a26446ce587daeeb4a97157ddb87e09eacc7 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 18 Sep 2024 12:55:02 +0200 Subject: [PATCH 2/5] add link to deploy docs --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 602bed2..6ca11c4 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Lightweight websocket->TCP proxy. Look at `main.go` for available configuration options. +Read more about how to deploy with Neon Serverless proxy: https://github.com/neondatabase/serverless/blob/main/DEPLOY.md + Run: ```bash From 43a087995b63e68e5919d1a148f9a48bd0f1d054 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 18 Sep 2024 13:01:03 +0200 Subject: [PATCH 3/5] add makefile for common scripts --- Makefile | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..740dbdc --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +GITHUB_USER=neondatabase +IMAGE_NAME=wsproxy +PLATFORMS=linux/amd64,linux/arm64 +BUILDER_NAME=$(IMAGE_NAME)-builder +REMOTE_TAG=ghcr.io/$(GITHUB_USER)/$(IMAGE_NAME) + +build: + docker build -t $(IMAGE_NAME) . + +run: + docker run --rm -p 80:80 -p 2112:2112 --name $(IMAGE_NAME) $(IMAGE_NAME) + +publish: + docker buildx create --use --name $(BUILDER_NAME) || true + docker buildx build --platform $(PLATFORMS) -t $(REMOTE_TAG) --push . + docker buildx rm $(BUILDER_NAME) \ No newline at end of file From 44956892b92aebdb6e7861399e06bf2d65a73714 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 18 Sep 2024 13:15:50 +0200 Subject: [PATCH 4/5] add neon + unix + drizzle example --- examples/with-unix-socket/.gitignore | 175 ++++++++++++++++++ examples/with-unix-socket/README.md | 24 +++ examples/with-unix-socket/bun.lockb | Bin 0 -> 30758 bytes examples/with-unix-socket/docker-compose.yaml | 28 +++ examples/with-unix-socket/index.ts | 37 ++++ examples/with-unix-socket/package.json | 16 ++ examples/with-unix-socket/tsconfig.json | 27 +++ 7 files changed, 307 insertions(+) create mode 100644 examples/with-unix-socket/.gitignore create mode 100644 examples/with-unix-socket/README.md create mode 100755 examples/with-unix-socket/bun.lockb create mode 100644 examples/with-unix-socket/docker-compose.yaml create mode 100644 examples/with-unix-socket/index.ts create mode 100644 examples/with-unix-socket/package.json create mode 100644 examples/with-unix-socket/tsconfig.json diff --git a/examples/with-unix-socket/.gitignore b/examples/with-unix-socket/.gitignore new file mode 100644 index 0000000..9b1ee42 --- /dev/null +++ b/examples/with-unix-socket/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/examples/with-unix-socket/README.md b/examples/with-unix-socket/README.md new file mode 100644 index 0000000..afa756a --- /dev/null +++ b/examples/with-unix-socket/README.md @@ -0,0 +1,24 @@ +# with-unix-socket + +Run Postgres instance with Unix socket and connect to it using Neon's WS Proxy and Drizzle ORM. + +This project was created using `bun init` in bun v1.1.27. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +docker compose up -d +NEON_WS_PROXY_HOST=$(docker compose port neon 80) bun run index.ts +``` + +To clean up: + +```bash +docker compose down +``` diff --git a/examples/with-unix-socket/bun.lockb b/examples/with-unix-socket/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..c42cd6656876272602503682871083fc5f92712c GIT binary patch literal 30758 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 literal 0 HcmV?d00001 diff --git a/examples/with-unix-socket/docker-compose.yaml b/examples/with-unix-socket/docker-compose.yaml new file mode 100644 index 0000000..705b567 --- /dev/null +++ b/examples/with-unix-socket/docker-compose.yaml @@ -0,0 +1,28 @@ +services: + pgsql: + image: timescale/timescaledb:latest-pg16 + restart: always + tmpfs: + - /var/lib/postgresql/data + volumes: + - pg_socket:/var/run/postgresql + environment: + POSTGRES_DB: neon-db + POSTGRES_USER: postgres + POSTGRES_PASSWORD: neon-password + + neon: + image: ghcr.io/flexchar/wsproxy:latest + restart: always + depends_on: + - pgsql + environment: + LOG_CONN_INFO: true + UNIX_SOCKET_PATH: "/var/run/postgresql/.s.PGSQL.5432" + volumes: + - pg_socket:/var/run/postgresql + ports: + - 80 + +volumes: + pg_socket: diff --git a/examples/with-unix-socket/index.ts b/examples/with-unix-socket/index.ts new file mode 100644 index 0000000..0e6ce18 --- /dev/null +++ b/examples/with-unix-socket/index.ts @@ -0,0 +1,37 @@ +import { Pool, neonConfig } from '@neondatabase/serverless'; +import { drizzle } from 'drizzle-orm/neon-serverless'; +import { sql } from 'drizzle-orm'; + +// Docs +// https://orm.drizzle.team/docs/get-started-postgresql#neon-postgres +// Test with +// NEON_WS_PROXY_HOST=$(docker compose port neon 80) bun run serverless.ts + +const NEON_WS_PROXY_HOST = process.env.NEON_WS_PROXY_HOST; +console.log('NEON_WS_PROXY_HOST', NEON_WS_PROXY_HOST); + +if (!NEON_WS_PROXY_HOST) { + throw new Error('NEON_WS_PROXY_HOST is not set'); +} + +// Set the WebSocket proxy to work with the local instance +neonConfig.wsProxy = () => `${process.env.NEON_WS_PROXY_HOST}/v1`; + +// Disable TLS when running on local machine +neonConfig.useSecureWebSocket = false; +// Disable all authentication and encryption +neonConfig.pipelineTLS = false; +neonConfig.pipelineConnect = false; + +const connectionString = `pgsql://postgres:neon-password@placeholder/neon-db`; + +const pool = new Pool({ connectionString }); +const db = drizzle(pool); + +const result = await db.execute(sql`SELECT version()`); +const res = result.rows[0]; + +console.log(res); + +await pool.end(); +process.exit(0); diff --git a/examples/with-unix-socket/package.json b/examples/with-unix-socket/package.json new file mode 100644 index 0000000..cc34411 --- /dev/null +++ b/examples/with-unix-socket/package.json @@ -0,0 +1,16 @@ +{ + "name": "with-unix-socket", + "module": "index.ts", + "type": "module", + "devDependencies": { + "@types/bun": "latest", + "drizzle-kit": "^0.24.2" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@neondatabase/serverless": "^0.9.5", + "drizzle-orm": "^0.33.0" + } +} \ No newline at end of file diff --git a/examples/with-unix-socket/tsconfig.json b/examples/with-unix-socket/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/examples/with-unix-socket/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} From 19323ff2c916e4294386add1271cd01a41b218b3 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 18 Sep 2024 13:21:44 +0200 Subject: [PATCH 5/5] add more comments --- examples/with-unix-socket/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/with-unix-socket/index.ts b/examples/with-unix-socket/index.ts index 0e6ce18..702be86 100644 --- a/examples/with-unix-socket/index.ts +++ b/examples/with-unix-socket/index.ts @@ -5,7 +5,7 @@ import { sql } from 'drizzle-orm'; // Docs // https://orm.drizzle.team/docs/get-started-postgresql#neon-postgres // Test with -// NEON_WS_PROXY_HOST=$(docker compose port neon 80) bun run serverless.ts +// NEON_WS_PROXY_HOST=$(docker compose port neon 80) bun run index.ts const NEON_WS_PROXY_HOST = process.env.NEON_WS_PROXY_HOST; console.log('NEON_WS_PROXY_HOST', NEON_WS_PROXY_HOST); @@ -18,12 +18,14 @@ if (!NEON_WS_PROXY_HOST) { neonConfig.wsProxy = () => `${process.env.NEON_WS_PROXY_HOST}/v1`; // Disable TLS when running on local machine -neonConfig.useSecureWebSocket = false; +neonConfig.useSecureWebSocket = false; // or true, if you, for example, expose using Cloudflare Tunnel // Disable all authentication and encryption neonConfig.pipelineTLS = false; neonConfig.pipelineConnect = false; const connectionString = `pgsql://postgres:neon-password@placeholder/neon-db`; +// "placeholder" can be any string just to satisfy Neon's connection string format, +// because we're using Unix socket, we don't need to specify the host and port at all. const pool = new Pool({ connectionString }); const db = drizzle(pool);