https://github.com/menci/tsukasa
A flexible port forwarder among TCP, UNIX socket and (optionally) Tailscale, with PROXY protocol support, written in Golang.
https://github.com/menci/tsukasa
Last synced: about 1 year ago
JSON representation
A flexible port forwarder among TCP, UNIX socket and (optionally) Tailscale, with PROXY protocol support, written in Golang.
- Host: GitHub
- URL: https://github.com/menci/tsukasa
- Owner: Menci
- License: mit
- Created: 2024-08-21T15:09:44.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-09-24T17:39:01.000Z (almost 2 years ago)
- Last Synced: 2025-04-18T15:17:34.462Z (over 1 year ago)
- Language: Go
- Size: 32.2 KB
- Stars: 13
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Tsusaka
Tsusaka is a flexible port forwarder among:
* TCP Ports
* UNIX Sockets
* Tailscale TCP Ports (without Tailscale daemon or TUN/TAP permission! This is made possible with [tsnet](https://tailscale.com/kb/1244/tsnet))
* Also supports SOCKS5/HTTP proxy feature of `tailscaled`.
* If you don't use Tailscale features, it won't initialize Tailscale components and just behaves like a local port forwarder.
It also supports passing the client IP with PROXY protocol (for listening on TCP or Tailscale TCP).
> The name Tsusaka comes from the character **Tenma Tsukasa** from the music visual novel game Project SEKAI. He is a member of the musical show unit "Wonderlands x Showtime". Tsukasa has bucketloads of confidence and loves to be the center of attention. A theater show he saw as a kid impressed him so much that he made it his ultimate goal to become the greatest star in the world.
# Development
Simply build the program with `go build` or build the Docker image with `docker build`.
# Usage
Use with command-line configuration:
```bash
./tsusaka --ts-hostname Tsusaka \
--ts-authkey "$TS_AUTHKEY" \
--ts-ephemeral false \
--ts-state-dir /var/lib/tailscale \
--ts-listen-socks5 localhost:1080 \
--ts-listen-http localhost:8080 \
--ts-verbose true \
nginx,listen=tailscale://0.0.0.0:80,connect=tcp://127.0.0.1:8080,log-level=info,proxy-protocol \
myapp,listen=unix:/var/run/myapp.sock,connect=tailscale://app-hosted-in-tailnet:8080
```
Or use with configuration file:
```yaml
# Tailscale configuration is not required and Tailsccale will not be loaded if no services with Tailscale defined.
tailscale:
hostname: Tsusaka
# `null` to Use `TS_AUTHKEY` from environment or interactive login.
authKey: null
ephemeral: false
stateDir: /var/lib/tailscale
listen:
socks5: 1080
http: 8080
verbose: true
services:
nginx:
listen: tailscale://0.0.0.0:80 # Only "0.0.0.0" and "::" allowed in Tailscale listener.
connect: tcp://127.0.0.1:8080
logLevel: info # "error" / "info" / "verbose". By default "info".
proxyProtocol: true # Listening on UNIX socket doesn't support PROXY protocol.
myapp:
listen: unix:/var/run/myapp.sock
connect: tailscale://app-hosted-in-tailnet:8080
```
Configuration file could be specified with command-line configuration options at the same time.
```bash
./tsusaka --conf tsusaka.yaml
```
You can also completely omit Tailscale-related configuration and use Tsukasa as a simple port forward between TCP port and UNIX socket.
# Docker
To use Tsukasa with Docker, it's recommended to start Tsusaka in the host network mode to ensure Tailscale's UDP hole punching to work (Docker's MASQUERADE routing is nearly blocking NAT traversal).
```bash
docker run \
--network=host \
-e TS_AUTHKEY="$TS_AUTHKEY" \
-v ./tailscale-state:/var/lib/tailscale \
ghcr.io/menci/tsusaka \
--ts-hostname Tsusaka \
--ts-state-dir /var/lib/tailscale \
myapp,listen=tcp://0.0.0.0:80,connect=tailscale://app-hosted-in-tailnet:8080
```
If you want to expose something in a container to your Tailnet, use UNIX socket and a shared volume. Here is an example with [Docker Compose](https://docs.docker.com/compose/). Note that if your application doesn't support listening on a UNIX socket, you can also start another instance of Tsukasa to work as a simple port forwarder from/to UNIX socket and TCP port in the virtual network.
```yaml
services:
initialize:
image: busybox
command: |
# The initialize container empties the shared-sockets directory each time.
rm -rf /socket/*
volumes:
- shared-sockets:/socket
tsukasa:
image: ghcr.io/menci/tsukasa
network_mode: host
depends_on:
initialize:
condition: service_completed_successfully
volumes:
- tailscale-state:/var/lib/tailscale
- shared-sockets:/socket
environment:
TS_AUTHKEY: ${TAILSCALE_AUTHKEY}
command:
- app,listen=tailscale://0.0.0.0:80,connect=unix:/socket/app.sock
app:
image: # Here comes your app, which listens on /socket/app.sock
depends_on:
initialize:
condition: service_completed_successfully
volumes:
- shared-sockets:/socket
command: my_app --listen /socket/app.sock
```