This guide walks through setting up a Ghostunnel server and client with mutual TLS, using a self-signed CA for testing.

Install Ghostunnel #

Terminal
# Homebrew
brew install ghostunnel

# Or pull a Docker image (see Docker docs for all variants)
docker pull ghostunnel/ghostunnel:latest-distroless

Pre-built binaries are also available on the GitHub releases page. See Docker Images for all available image variants.

To build from source (requires Go), clone the repository and run:

Terminal
go tool mage go:build

Generate Test Certificates #

If you already maintain a PKI, you can skip this step and use your existing certificates. The steps below generate certificates for testing and development only.

You need a CA, a server certificate, and a client certificate. The rest of this guide uses the paths from test-keys/, so adjust if you use a different method.

From the Ghostunnel repo (requires Go):

Terminal
go tool mage test:keys

This creates a test-keys/ directory with everything you need: CA cert, server cert+key, client cert+key, and PKCS#12 keystores.

Using cfssl: cfssl is a full-featured PKI toolkit that can generate CAs and sign certificates. See the cfssl documentation for usage.

Using OpenSSL manually: see the openssl-req and openssl-x509 docs for creating CAs and signing certificates.

Start a Backend Service #

Ghostunnel is protocol-agnostic and works with any TCP-based protocol, not just HTTP. For this demo we’ll use a simple HTTP server as the backend:

Terminal
python3 -m http.server 8080 &

Run Ghostunnel Server #

In a new terminal, start a server that listens for TLS on port 8443 and forwards plaintext to the backend on port 8080. Only clients with CN=client are allowed:

Terminal
ghostunnel server \
    --listen localhost:8443 \
    --target localhost:8080 \
    --cert test-keys/server-cert.pem \
    --key test-keys/server-key.pem \
    --cacert test-keys/cacert.pem \
    --allow-cn client

Run Ghostunnel Client #

In another terminal, start a client that listens for plaintext on port 8081 and connects to the server over TLS:

Terminal
ghostunnel client \
    --listen localhost:8081 \
    --target localhost:8443 \
    --cert test-keys/client-cert.pem \
    --key test-keys/client-key.pem \
    --cacert test-keys/cacert.pem

Test the Tunnel #

In a third terminal, send a request through the tunnel:

Terminal
curl http://localhost:8081

You should see the directory listing from the Python HTTP server. The connection between client and server is encrypted with mTLS, even though curl speaks plain HTTP.


Tunnel diagram

The Ghostunnel client accepted a plaintext connection from curl, wrapped it in TLS with the client certificate, and forwarded it to the Ghostunnel server. The server verified the client cert (CN=client), unwrapped TLS, and forwarded the plaintext request to the backend.

Next Steps #