ngroklink provides a way to connect to remote services through a secure agent-to-agent tunnel without requiring direct access to those services. It creates secure connections between your local machine and remote services through the ngrok edge network.
ngroklink establishes secure connections using an agent-to-agent architecture:
- Remote Agent: A remote ngrok agent runs in proximity to the services you want to access.
- Local Agent (ngroklink): The ngroklink tool on your local machine acts as the local agent.
- Secure Connection: The two agents establish an encrypted tunnel through ngrok's edge network.
- Service Access: Traffic flows from your local applications through the tunnel to the remote services.
This architecture provides several advantages:
- No direct exposure of services to the internet
- End-to-end encryption between agents
- No need for complex VPN setups
- Access to services across network boundaries
┌─────────────┐ ┌───────────────┐ ┌────────────────┐ ┌─────────────┐
│ │ │ │ │ │ │ │
│ Local │━━━━▶│ ngroklink │━━━━▶│ Remote ngrok │━━━━▶│ Remote │
│ Application │ │ (Local Agent) │ │ Agent │ │ Service │
│ │ │ │ │ │ │ │
└─────────────┘ └───────────────┘ └────────────────┘ └─────────────┘
Before using ngroklink on your local machine, you need to set up the remote ngrok agent at the service location.
- Download the ngrok agent from ngrok.com for the appropriate platform
- Install and authenticate the agent using your authtoken:
ngrok config add-authtoken YOUR_AUTHTOKEN
You can start the remote agent in one of two ways:
For TCP services:
ngrok tcp <port for your service> --url tcp://service.identifier:port --binding kubernetes
For HTTP services:
ngrok http <port for service> --url http://service.identifier --binding kubernetes
Replace <port for your service>
with the actual port your service is running on, and service.identifier
with a unique identifier for your service.
For more complex setups, you can use the ngrok configuration file:
- Create a
ngrok.yml
file with your endpoint definitions - Start the agent with this configuration:
ngrok start --all
Example configuration:
version: 3
agent:
authtoken: YOUR_AUTHTOKEN
endpoints:
- name: my-http-service
url: http://service.identifier
binding: kubernetes
upstream:
url: http://localhost:8080
- name: my-tcp-service
url: tcp://service.identifier:5432
binding: kubernetes
upstream:
url: tcp://localhost:5432
For more advanced configuration options, refer to the ngrok configuration documentation.
ngroklink provides platform-specific installation scripts to help you get started quickly:
- Download the appropriate zip file for your platform (e.g.,
ngroklink-darwin-arm64.zip
for Apple Silicon Macs). - Extract the zip file.
- Run the installation script:
This will install ngroklink to
# For macOS ./install-macos.sh # For Linux ./install-linux.sh
/usr/local/bin
so you can run it from anywhere.
- Download the Windows zip file (
ngroklink-windows-amd64.zip
). - Extract the zip file.
- Run the
install-windows.bat
script and follow the prompts.
After installation, configure ngroklink with your ngrok credentials:
ngroklink --ngrok-api-key=YOUR_API_KEY --ngrok-authtoken=YOUR_AUTH_TOKEN
This will save your configuration to ~/.ngrok-agent/config.yaml
for future use. You only need to do this once, or when you want to update your credentials.
If you need to start fresh or are redistributing ngroklink, you can clean up the existing configuration using the provided cleanup script:
./clean-config.sh
This will backup and remove your existing configuration file, allowing you to set up ngroklink again with new credentials.
ngroklink can be used in several ways:
In server mode, the agent connects to the ngrok API, registers with the remote agent, and starts all configured connections. To start the server mode with all your connections:
./ngroklink connect --all
This will start all your saved connections simultaneously, allowing you to access multiple services at once.
In connect mode, the agent creates a local forwarding to a specific remote endpoint without saving it to the configuration. This is useful for temporary connections or quick testing.
./ngroklink connect ENDPOINT_URL --port=LOCAL_PORT_OR_HOSTPORT
Where:
ENDPOINT_URL
is in the formatprotocol://service.identifier:port
(e.g.,tcp://myservice.prod:80
)--port
can be either:- Just a port number (e.g.,
8080
) - This binds to localhost - A host:port combination (e.g.,
192.168.1.10:8080
) - This binds to the specific interface
- Just a port number (e.g.,
Examples:
# Listen on localhost:8080
./ngroklink connect tcp://nginx.prod:80 --port=8080
# Listen on a specific network interface 192.168.1.10:8080
./ngroklink connect tcp://nginx.prod:80 --port=192.168.1.10:8080
# Listen on localhost but explicitly specify it
./ngroklink connect http://webapp.prod:80 --port=localhost:8080
The connection is established through the remote agent to the specified service. You can then access the service by connecting to your specified local address.
The agent provides commands to manage persistent connections that will be started automatically in server mode:
./ngroklink add --name=CONNECTION_NAME --url=ENDPOINT_URL --port=LOCAL_PORT_OR_HOSTPORT [--description=DESCRIPTION]
Examples:
# Using just port (binds to localhost)
./ngroklink add --name=nginx --url=tcp://nginx.prod:80 --port=8080 --description="Nginx web server"
# Using host:port format to bind to a specific interface
./ngroklink add --name=nginx-specific --url=tcp://nginx.prod:80 --port=192.168.1.10:8080 --description="Nginx on specific interface"
This saves a named connection to your configuration file. You can add multiple connections and start them all at once with the server mode.
./ngroklink edit CONNECTION_NAME [--url=ENDPOINT_URL] [--port=LOCAL_PORT_OR_HOSTPORT] [--description=DESCRIPTION]
Example:
# Update to use a specific IP binding
./ngroklink edit nginx --port=192.168.1.5:8080 --description="Updated nginx server with specific binding"
This updates the connection settings while keeping any non-specified settings unchanged.
./ngroklink list
This displays all configured connections with their details, including any specific host bindings.
./ngroklink remove CONNECTION_NAME
Removes a connection from your configuration.
./ngroklink start CONNECTION_NAME
Starts a single named connection instead of all connections. This is useful when you only need one specific service.
You can directly edit the configuration file using your default text editor:
./ngroklink config edit
This opens the ~/.ngrok-agent/config.yaml
file in your default editor (determined by the EDITOR
environment variable, or defaults to nano).
The agent provides comprehensive help information:
# Display general help
./ngroklink --help
# Display help for a specific command
./ngroklink help COMMAND
# Or use the -h/--help flag with any command
./ngroklink COMMAND --help
Example:
./ngroklink help connect
./ngroklink config edit --help
The agent stores its configuration in ~/.ngrok-agent/config.yaml
. The file contains:
- Agent configuration with your ngrok credentials
- A list of persistent connections
You can manually edit this file using the config edit
command or use the CLI commands to manage your connections.
# Agent Configuration (Required)
connections_agent:
authtoken: YOUR_AUTH_TOKEN
api-key: YOUR_API_KEY
# Connections Definitions
connections:
- name: example1
description: Service 1 Description
url: tcp://service1.prod:8080
localport: 8080
- name: example2
description: Service 2 Description
url: http://service2.prod:80
localport: 8081
localhost: 192.168.1.10 # Optional: specify binding interface
Note that:
- The
localport
field is always required and specifies the port number - The
localhost
field is optional and specifies a specific host/interface to bind to - If
localhost
is not specified or is empty, the connection binds to localhost (127.0.0.1) - Optional fields like
description
can be omitted, and the agent will use default values
Here's a more comprehensive example configuration with various types of services and binding options:
connections_agent:
authtoken: 2ath1n3BXXtgPYwQmf9H1ubQXhVX_5XAjfZbeVzi7UYfudWXmD
api-key: 2ath1q8TtdYye79qPAqTFSXcJJJi_4bciJZSYa4YfzGAsL2Jpn
connections:
- name: nginx
description: Nginx web server
url: tcp://nginx.prod:80
localport: 8080
# No localhost specified - binds to 127.0.0.1 (default)
- name: api-service
description: REST API service with specific binding
url: http://api-service.backend:8000
localport: 3000
localhost: 192.168.1.5 # Binds to this specific interface
- name: postgres
description: PostgreSQL database
url: tcp://postgres.database:5432
localport: 5432
- name: grpc-service
description: gRPC service on all interfaces
url: tcp://grpc-service.services:50051
localport: 50051
localhost: 0.0.0.0 # Binds to all available network interfaces
With this configuration:
- Accessing
localhost:8080
would connect to the Nginx service through the remote agent - Accessing
192.168.1.5:3000
would connect to the API service through the remote agent - Accessing
localhost:5432
would connect to the PostgreSQL database through the remote agent - Accessing
<any-local-ip>:50051
would connect to the gRPC service through the remote agent (since it's bound to all interfaces)
Connect to a development environment:
./ngroklink add --name=dev-frontend --url=http://frontend.dev:80 --port=3000 --description="Development Frontend"
./ngroklink add --name=dev-api --url=http://api.dev:8000 --port=8000 --description="Development API"
./ngroklink
Connect to a database through the remote agent:
./ngroklink connect tcp://mysql.database:3306 --port=3306
Then use your database client to connect to localhost:3306
.
Access services on different network interfaces:
# Bind to WiFi interface for a web app
./ngroklink add --name=webapp --url=http://webapp.prod:80 --port=192.168.1.5:8080
# Bind to Ethernet interface for a database
./ngroklink add --name=database --url=tcp://db.prod:5432 --port=10.0.0.5:5432
# Bind to all interfaces for a monitoring service
./ngroklink add --name=monitoring --url=http://monitoring.prod:3000 --port=0.0.0.0:3000
Allow multiple users on the same network to access a service:
# Bind to all interfaces
./ngroklink connect tcp://shared-service.prod:80 --port=0.0.0.0:8080
Other users on the network can now access the service via your machine's IP address.
When you start a connection with ngroklink, the following steps occur:
- Authentication: ngroklink authenticates with the ngrok API using your API key.
- Certificate Generation: A client certificate signing request (CSR) is generated locally.
- Certificate Signing: The CSR is sent to the ngrok API and signed.
- Agent Registration: ngroklink registers itself as a local agent.
- Binding Connection: A TLS connection is established to the ngrok edge (binding-ingress.ngrok.io:443).
- Connection Upgrade: The TLS connection is upgraded to a binding connection with information about the remote service.
- Local Listener: A TCP listener is started on your specified local port and interface.
- Traffic Forwarding: Each connection accepted on the local interface is paired with a new binding connection to the remote agent.
- End-to-End Flow: Traffic flows from your local application ➔ ngroklink ➔ ngrok edge ➔ remote agent ➔ remote service.
This allows you to securely connect to remote services without direct access to the remote network.
ngroklink implements multiple security layers:
- API Authentication: Your ngrok API key authenticates requests to the ngrok API.
- Certificate-Based Authentication: Client certificates ensure only authorized agents can establish connections.
- TLS Encryption: All traffic between agents is encrypted using TLS.
- Mutual Authentication: Both the local and remote agents authenticate each other.
- Limited Scope: Each connection only provides access to the specific service defined in the configuration.
- Local File Security: The configuration file is stored with restricted permissions (0600).
If you encounter connection issues, verify:
- Your ngrok credentials are correct and have the necessary permissions
- The remote agent is properly configured and running
- The service identifier in the URL is correct (e.g., service.identifier)
- The service is accessible from the remote agent
- Your local port is not already in use by another application
- If using a specific interface, ensure it exists and is accessible
If you see connection refused
errors when trying to connect to your local port:
- Check that ngroklink is running
- Verify that you're connecting to the correct port and interface
- Make sure the remote service identifier exists and is accessible from the remote agent
If you encounter authentication errors:
- Ensure your API key and authtoken are correct
- Check that your ngrok account has permissions to create agent bindings
If you see errors about binding to an address:
- Ensure the port is not already in use
- Check that you have permissions to bind to the specified port (ports below 1024 typically require elevated privileges)
- Verify that the interface/IP you specified exists on your system
If connections are slow to establish:
- The first connection might take longer as the agent needs to generate and sign a client certificate
- Subsequent connections should be faster
- ngroklink stores your ngrok credentials in
~/.ngrok-agent/config.yaml
. Ensure this file has appropriate permissions (the agent sets 0600 permissions automatically). - Client certificates are generated on-the-fly and stored in temporary files that are removed after use.
- All connections are secured with TLS.
- The agent uses mutual TLS authentication with the ngrok binding endpoint.
- When binding to 0.0.0.0 (all interfaces), be aware that other users on your network may be able to access the service through your machine.
- Consider using specific interface bindings instead of 0.0.0.0 when security is a concern.