@@ -5,10 +5,14 @@ A PostgreSQL wire protocol compatible server backed by DuckDB. Connect with any
55## Features
66
77- ** PostgreSQL Wire Protocol** : Full compatibility with PostgreSQL clients
8+ - ** TLS Encryption** : Required TLS connections with auto-generated self-signed certificates
89- ** Per-User Databases** : Each authenticated user gets their own isolated DuckDB database file
9- - ** Simple Password Authentication** : Username/password authentication (cleartext)
10- - ** Extended Query Protocol** : Support for prepared statements and parameterized queries
11- - ** SQL Compatibility** : Run most SQL queries that DuckDB supports
10+ - ** Password Authentication** : MD5 password authentication
11+ - ** Extended Query Protocol** : Support for prepared statements, binary format, and parameterized queries
12+ - ** DuckDB Extensions** : Configurable extension loading (ducklake enabled by default)
13+ - ** DuckLake Integration** : Auto-attach DuckLake catalogs for lakehouse workflows
14+ - ** Rate Limiting** : Built-in protection against brute-force attacks
15+ - ** Flexible Configuration** : YAML config files, environment variables, and CLI flags
1216
1317## Quick Start
1418
@@ -24,39 +28,137 @@ go build -o duckgres .
2428./duckgres
2529```
2630
27- The server starts on port 5432 by default. Database files are stored in ` ./data/ ` .
31+ The server starts on port 5432 by default with TLS enabled . Database files are stored in ` ./data/ ` . Self-signed certificates are auto-generated in ` ./certs/ ` if not present .
2832
2933### Connect
3034
3135``` bash
32- # Using psql
33- PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres
36+ # Using psql (sslmode=require is needed for TLS)
37+ PGPASSWORD=postgres psql " host= localhost port= 5432 user= postgres sslmode=require "
3438
3539# Or with any PostgreSQL driver
3640```
3741
3842## Configuration
3943
40- Configuration is currently done in ` main.go ` :
41-
42- ``` go
43- cfg := server.Config {
44- Host : " 0.0.0.0" ,
45- Port : 5432 ,
46- DataDir : " ./data" ,
47- Users : map [string ]string {
48- " postgres" : " postgres" ,
49- " alice" : " alice123" ,
50- " bob" : " bob123" ,
51- },
52- }
44+ Duckgres supports three configuration methods (in order of precedence):
45+ 1 . CLI flags (highest priority)
46+ 2 . Environment variables
47+ 3 . YAML config file
48+ 4 . Built-in defaults (lowest priority)
49+
50+ ### YAML Configuration
51+
52+ Create a ` duckgres.yaml ` file (see ` duckgres.example.yaml ` for a complete example):
53+
54+ ``` yaml
55+ host : " 0.0.0.0"
56+ port : 5432
57+ data_dir : " ./data"
58+
59+ tls :
60+ cert : " ./certs/server.crt"
61+ key : " ./certs/server.key"
62+
63+ users :
64+ postgres : " postgres"
65+ alice : " alice123"
66+
67+ extensions :
68+ - ducklake
69+ - httpfs
70+
71+ ducklake :
72+ metadata_store : " postgres:dbname=ducklake"
73+ data_path : " s3://my-bucket/ducklake-data/"
74+
75+ rate_limit :
76+ max_failed_attempts : 5
77+ failed_attempt_window : " 5m"
78+ ban_duration : " 15m"
79+ max_connections_per_ip : 100
80+ ` ` `
81+
82+ Run with config file:
83+
84+ ` ` ` bash
85+ ./duckgres --config duckgres.yaml
86+ ```
87+
88+ ### Environment Variables
89+
90+ | Variable | Description | Default |
91+ | ----------| -------------| ---------|
92+ | ` DUCKGRES_CONFIG ` | Path to YAML config file | - |
93+ | ` DUCKGRES_HOST ` | Host to bind to | ` 0.0.0.0 ` |
94+ | ` DUCKGRES_PORT ` | Port to listen on | ` 5432 ` |
95+ | ` DUCKGRES_DATA_DIR ` | Directory for DuckDB files | ` ./data ` |
96+ | ` DUCKGRES_CERT ` | TLS certificate file | ` ./certs/server.crt ` |
97+ | ` DUCKGRES_KEY ` | TLS private key file | ` ./certs/server.key ` |
98+ | ` DUCKGRES_DUCKLAKE_METADATA_STORE ` | DuckLake metadata store | - |
99+ | ` DUCKGRES_DUCKLAKE_DATA_PATH ` | DuckLake data path | - |
100+
101+ ### CLI Flags
102+
103+ ``` bash
104+ ./duckgres --help
105+
106+ Options:
107+ -config string Path to YAML config file
108+ -host string Host to bind to
109+ -port int Port to listen on
110+ -data-dir string Directory for DuckDB files
111+ -cert string TLS certificate file
112+ -key string TLS private key file
113+ ```
114+
115+ ## DuckDB Extensions
116+
117+ Extensions are automatically installed and loaded when a user's database is first opened. The ` ducklake ` extension is enabled by default.
118+
119+ ``` yaml
120+ extensions :
121+ - ducklake # Default - DuckLake lakehouse format
122+ - httpfs # HTTP/S3 file system access
123+ - parquet # Parquet file support (built-in)
124+ - json # JSON support (built-in)
125+ - postgres # PostgreSQL scanner
53126` ` `
54127
55- ### Users
128+ ## DuckLake Integration
56129
57- Each user in the ` Users ` map gets:
58- - Their own DuckDB database file at ` ./data/{username}.db `
59- - Complete isolation from other users' data
130+ DuckLake provides a SQL-based lakehouse format. When configured, the DuckLake catalog is automatically attached on connection:
131+
132+ ` ` ` yaml
133+ ducklake :
134+ # Metadata store (required to enable DuckLake catalog)
135+ metadata_store : " postgres:host=localhost dbname=ducklake"
136+ # Data path for table files
137+ data_path : " s3://my-bucket/ducklake-data/"
138+ ` ` `
139+
140+ This runs the equivalent of:
141+ ` ` ` sql
142+ ATTACH 'ducklake:postgres:host=localhost dbname=ducklake' (DATA_PATH 's3://my-bucket/ducklake-data/')
143+ ```
144+
145+ See [ DuckLake documentation] ( https://ducklake.select/docs/stable/duckdb/usage/connecting ) for more details.
146+
147+ ## Rate Limiting
148+
149+ Built-in rate limiting protects against brute-force authentication attacks:
150+
151+ - ** Failed attempt tracking** : Bans IPs after too many failed auth attempts
152+ - ** Connection limits** : Limits concurrent connections per IP
153+ - ** Auto-cleanup** : Expired records are automatically cleaned up
154+
155+ ``` yaml
156+ rate_limit :
157+ max_failed_attempts : 5 # Ban after 5 failures
158+ failed_attempt_window : " 5m" # Within 5 minutes
159+ ban_duration : " 15m" # Ban lasts 15 minutes
160+ max_connections_per_ip : 100 # Max concurrent connections
161+ ` ` `
60162
61163## Usage Examples
62164
@@ -90,7 +192,7 @@ GROUP BY name;
90192│ PostgreSQL │
91193│ Client (psql) │
92194└────────┬────────┘
93- │ PostgreSQL Wire Protocol
195+ │ PostgreSQL Wire Protocol (TLS)
94196 ▼
95197┌─────────────────┐
96198│ Duckgres │
@@ -101,12 +203,15 @@ GROUP BY name;
101203┌─────────────────┐
102204│ DuckDB │
103205│ (per-user db) │
206+ │ + Extensions │
207+ │ + DuckLake │
104208└─────────────────┘
105209```
106210
107- ## Supported SQL Commands
211+ ## Supported Features
108212
109- - ` SELECT ` - Full query support
213+ ### SQL Commands
214+ - ` SELECT ` - Full query support with binary result format
110215- ` INSERT ` - Single and multi-row inserts
111216- ` UPDATE ` - With WHERE clauses
112217- ` DELETE ` - With WHERE clauses
@@ -115,10 +220,15 @@ GROUP BY name;
115220- ` ALTER TABLE `
116221- ` BEGIN/COMMIT/ROLLBACK ` (DuckDB transaction support)
117222
223+ ### PostgreSQL Compatibility
224+ - Extended query protocol (prepared statements)
225+ - Binary and text result formats
226+ - MD5 password authentication
227+ - Basic ` pg_catalog ` system tables for client compatibility
228+ - ` \dt ` , ` \d ` , and other psql meta-commands
229+
118230## Limitations
119231
120- - ** No SSL/TLS** : Connections are unencrypted
121- - ** Text Format Only** : Results are returned in text format (no binary protocol)
122232- ** Single Process** : Each user's database is opened in the same process
123233- ** No Replication** : Single-node only
124234- ** Limited System Catalog** : Some ` pg_* ` system tables are not available
0 commit comments