A tsnet application letting Tailscale nodes access databases from anywhere using their Tailscale identity to authenticate.
The ts-db-connector is a tsnet application that runs as a single Tailscale node and proxies database connections over your tailnet.
Configuration is stored in HuJSON format (JSON with comments) and loaded via the --config flag. Field values can reference environment variables using the env: prefix or files using the file: prefix.
| Field | Purpose | Default | Well-known Env Var |
|---|---|---|---|
control_url |
Tailscale control server URL (must be http/https without trailing slash) | https://login.tailscale.com |
TS_SERVER |
state_dir |
Directory for persistent Tailscale state | ./data/ts-db-connector |
TS_STATE_DIR |
hostname |
Hostname for the Tailscale node (1-63 chars, letters/numbers/hyphens) | ts-db-connector |
TS_HOSTNAME |
authkey |
Tailscale auth key for joining the tailnet | (empty) | TS_AUTHKEY |
client_id |
OAuth/Workload Identity client ID | (empty) | TS_CLIENT_ID |
client_secret |
OAuth client secret | (empty) | TS_CLIENT_SECRET |
id_token |
Workload Identity ID token | (empty) | ID_TOKEN |
Note: At least one authentication method (auth_key, client credentials, or ID token) should be provided unless already connected to the tailnet.
| Field | Purpose | Default |
|---|---|---|
admin_port |
HTTP port for admin API and debug endpoints | 8080 |
Each database is defined in the databases object with a unique key. All fields support env: and file: prefixes to load field value from references.
Sensitive information should always be provided from a secured reference.
| Field | Purpose | Default |
|---|---|---|
engine |
Database type | (required) |
host |
Database server hostname or IP | localhost |
port |
Database server port (0-65535) | Engine-specific e.g. Postgres=5432, MongoDB=27017 |
listening_port |
Port where connector listens for Tailscale connections | Same as port |
ca_file |
Path to database TLS CA certificate | (required) |
admin_user |
Database admin user for managing ephemeral credentials | (required) |
admin_password |
Database admin password for managing ephemeral credentials | (required) |
{
// Comments are allowed in HuJSON format
"tailscale": {
"control_url": "https://login.tailscale.com",
"hostname": "my-db-connector",
"authkey": "env:TS_AUTHKEY"
},
"connector": {
"admin_port": 8080
},
"databases": {
"production-pg": {
"engine": "postgres",
"host": "pg.internal.example.com",
"port": 5432,
"ca_file": "./certs/pg-ca.crt",
"admin_user": "connector_admin",
"admin_password": "file:/secrets/pg-admin-password"
},
"analytics-crdb": {
"engine": "cockroachdb",
"host": "crdb.internal.example.com",
"port": 26257,
"ca_file": "./certs/crdb-ca.crt",
"admin_user": "root",
"admin_password": "env:CRDB_ADMIN_PASSWORD"
}
}
}{
"databases": {
"production-pg": {
"engine": "postgres",
"ca_file": "./certs/pg-ca.crt",
"admin_user": "connector_admin",
"admin_password": "file:/secrets/pg-admin-password"
}
}
}make dev- Build with debug flagsmake build- Build with release settingsmake containers- Start test containers for local developmentmake run- Build and run the connector for local developmentmake test- Run unit testsmake test_acc- Run unit & acceptance tests
-
(Optional) Start your custom Tailscale control server if not using https://login.tailscale.com/
./path/to/local/tailscale/server
-
Set the
TS_SERVERenvironment variable to point to your Tailscale control server for future steps.export TS_SERVER=https://login.tailscale.com # http://localhost:31544 for local control
-
Connect your workstation to a tailnet on your Tailscale control server.
tailscale up --login-server=$TS_SERVER -
Configure the databases capability in your tailnet policy file. The example below works out of the box with the test database containers provided for local development. ($TS_SERVER/admin/acls/file)
{ "tagOwners": { "tag:ts-db-connectors": ["autogroup:admin"] }, "grants": [ { "src": ["*"], "dst": ["tag:ts-db-connectors"], "ip": [ "tcp:5432", "tcp:26257", "tcp:27017", "tcp:8080", ], "app": { "tailscale.com/cap/databases": [ { "my-postgres-1": { "engine": "postgres", "access": [ { "databases": ["testdb"], "roles": ["test"] } ] }, "my-cockroachdb-1": { "engine": "cockroachdb", "access": [ { "databases": ["testdb"], "roles": ["test"] } ] }, "my-mongodb-1": { "engine": "mongodb", "access": [ { "databases": ["testdb"], "roles": ["test"] } ] } } ] } } ] } -
Create an authkey so the ts-db-connector can join your tailnet. All databases will be accessible via a single node with hostname "ts-db-connector". ($TS_SERVER/admin/settings/keys)
-
Set the
TS_AUTHKEYenvironment variable with the authkey you created for future steps.export TS_AUTHKEY=tskey-auth-1234 # reusable ephemeral key is recommended for quick iterations
-
Run docker compose to start pre-configured test database containers. This will set up the databases and update a
data/.config.hujsonconfig file with the database entries. By default, the development ts-db-connector uses that config file.# Start all database engines (default) make containers # Start only specific database engines make containers SERVICES="postgres" make containers SERVICES="postgres cockroachdb" make containers SERVICES="mongodb"
-
Run the ts-db-connector on your host machine.
# Use default config file (data/.config.hujson) make run # Use a custom config file make run CONFIG=path/to/your/config.json
The connector will join your tailnet and start serving database connections over Tailscale.
-
Connect to the databases over Tailscale, works from anywhere without credentials. All databases are accessible via the ts-db-connector hostname on their respective ports.
# Connect to Postgres psql -h ts-db-connector -p 5432 -U test -d testdb # Connect to CockroachDB psql -h ts-db-connector -p 26257 -U test -d testdb # Connect to MongoDB mongosh "mongodb://test:test@ts-db-connector:27017/testdb"
By default, the acceptance tests run against testcontrol, an in-memory fake control server that we also use to test other parts of Tailscale. We're planning to decouple this setup further in the near future so that the same test scenarios can be run against a real tailnet and control server.
The tests use testcontainers-go to create containerised databases instances.
If your container management tool places the Docker socket file in a non-standard location, you need to symlink that location to /var/run/docker.sock.
sudo ln -s $DOCKER_SOCKET_FILE_LOCATION /var/run/docker.sock
Alternatively, if you don't want this to apply globally, set the DOCKER_HOST environment variable to that custom location.
To run the unit & acceptance tests
make test_acc
To run only the unit tests
make test
