Isolate service, HTTP/2, TLS, streaming, and tunnel failures one checkpoint at a time
A gRPC endpoint can accept a connection and still fail during service discovery, method invocation, streaming, or final status delivery. This guide uses grpcurl to establish a known-good local baseline and repeat the same calls through a Localtonet TCP tunnel. You will test reflection or local descriptors, certificate validation, request authority, deadlines, every streaming pattern, and the final gRPC status. Because current first-party Localtonet evidence does not establish native gRPC compatibility for every HTTP/s or TLS tunnel configuration, this tutorial narrows its reproducible workflow to the raw TCP tunnel family and requires verification of the complete gRPC exchange.
π What's in this guide
Build a local-to-public diagnostic model
Testing an ordinary web endpoint often begins with a browser or a basic HTTP request. Native gRPC needs a more specialized approach. Its messages are usually encoded with Protocol Buffers, methods are selected using a fully qualified service and method path, calls rely on HTTP/2 semantics, and the final operation result is commonly communicated in HTTP trailers. A successful TCP connection proves only that something accepted the connection. It does not prove that the complete gRPC exchange succeeded.
grpcurl is the official open-source command-line client used throughout this guide. It can discover descriptors through gRPC server reflection, read local .proto or compiled protoset files, convert JSON input into protobuf messages, invoke RPC methods, and decode responses. The official project supports unary, client-streaming, server-streaming, and bidirectional-streaming methods.
The most dependable tunnel test is comparative. First, make a successful call directly to the service from the device where grpcurl is running. Record the destination, TLS mode, descriptor source, method, request, metadata, timing, response, and final status. Then start the Localtonet tunnel and repeat the same logical call against its assigned public host and port. Change only the destination and transport values that must differ.
This creates a practical decision boundary:
- If the local call fails, repair the application, listener, descriptors, request, credentials, or local TLS configuration before investigating the tunnel.
- If the local call succeeds but the public connection cannot be established, check the Localtonet client, tunnel lifecycle, public endpoint, and local target.
- If the public connection opens but grpcurl cannot establish the expected protocol, investigate TLS mode, certificate identity, HTTP/2 establishment, or whether the public endpoint targets the correct local listener.
- If unary calls succeed but streams fail, focus on deadlines, stream lifetime, standard-input completion, buffering, cancellation, and final trailer delivery.
- If response messages arrive but the command ends in error, inspect the final gRPC status instead of treating the visible messages as proof of success.
TCP connectivity, TLS negotiation, HTTP/2 establishment, gRPC method routing, protobuf decoding, application authorization, message streaming, and trailer delivery are separate checkpoints. Preserve the exact error from each checkpoint instead of reducing every failure to βthe tunnel is down.β
Understand the protocol details that affect tunneled gRPC
Native gRPC uses HTTP/2 to carry headers, length-prefixed protobuf messages, and trailers. HTTP/2 can multiplex multiple streams on a connection, while each RPC has its own lifecycle. For protocol-level detail, consult the official gRPC HTTP/2 protocol specification and the broader official gRPC documentation.
:authority pseudo-header identifies the intended host. Virtual-host routing and certificate hostname validation may depend on the authority rather than only the destination IP address.
grpc-status and, when present, grpc-message. Receiving response messages does not guarantee that the call completed successfully.
Plaintext gRPC is still HTTP/2
In grpcurl, -plaintext means that the connection does not use TLS. It does not switch native gRPC to HTTP/1.1. A cleartext gRPC listener still expects HTTP/2 semantics. Do not use -plaintext merely to suppress a certificate error, because it changes the transport instead of repairing certificate validation.
Reflection supplies descriptors, not authorization
The official gRPC reflection guide explains how reflection lets tools request service descriptors from a running server. Reflection does not bypass application authentication or authorization. A protected application method still requires valid credentials and remains subject to the server's authorization policy.
Reflection can reveal service names, method names, and message schemas. Many deployments therefore disable it outside development or protect it with authorization. If reflection is unavailable, grpcurl can use local proto source files or a compiled descriptor set. A failed list command may indicate only that reflection is disabled, not that application RPCs are unreachable.
Trailers are part of the result
A server may emit one or more valid response messages and then finish with a non-success status. If an intermediate path closes the stream without preserving the final trailers, grpcurl may report an unexpected end of stream or another transport error rather than the application status the server intended.
This distinction is especially important for server-streaming and bidirectional methods. Always inspect the final grpcurl result and process exit status. Do not stop reading as soon as the first response object appears.
Collect prerequisites and install grpcurl
Before exposing anything publicly, collect enough information to reproduce the service locally. Do not guess the port, transport mode, service name, or credentials.
Service information you need
- The local hostname or IP address on which the gRPC server listens.
- The actual listening port.
- Whether the listener expects TLS or cleartext HTTP/2.
- The fully qualified service and method names, such as
example.v1.ExampleService/GetItem. - A valid request for one small unary method.
- Whether server reflection is enabled.
- If reflection is unavailable, the required proto files, import directories, or protoset file.
- Required application metadata and authorization credentials.
- The expected response and normal completion status.
- For a streaming method, the expected message sequence and the event that completes the stream.
You also need the Localtonet client installed and running on a device that can reach the gRPC listener. The service can be on the same device or another locally reachable machine. What matters is that the target IP address and port are reachable from the selected Localtonet client device.
Use an official grpcurl installation path
The official grpcurl installation guidance documents binaries, Homebrew, Docker, Snap, and source installation. The official grpcurl releases page provides release artifacts. Package repositories can lag behind the current project release, so record the version used for a diagnostic.
On macOS with Homebrew:
brew install grpcurl
On a system with Snap:
snap install grpcurl
If a supported Go SDK is installed:
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
The Go command installs the executable in the Go binary directory. If your shell cannot find it, add that directory to PATH or invoke the executable using its full path.
Confirm the binary and inspect its current options:
grpcurl -version
grpcurl -help
The official container image is useful when installing a local binary is undesirable:
docker pull ghcr.io/fullstorydev/grpcurl:latest
docker run ghcr.io/fullstorydev/grpcurl:latest api.grpc.me:443 list
Containers introduce additional networking rules. On macOS and Windows, a container normally reaches a service on the host through host.docker.internal, not the container's own localhost. On Linux, Docker host networking can be used where appropriate. Proto files and protosets must be mounted into the container. Add Docker's -i option when grpcurl must read streaming messages from standard input.
Bearer tokens, client keys, certificate paths, private endpoint details, and sensitive request data can be retained in shell history, process listings, terminal recordings, and CI logs. Use your organization's approved secret-handling process and redact captures before sharing them.
Prove the gRPC service locally before tunneling it
The examples use localhost:50051 and fictional service names. These are placeholders, not Localtonet defaults. Replace them with values verified from your service configuration.
1. Match the listener's TLS mode
Use -plaintext only for a listener intentionally configured without TLS:
grpcurl -plaintext localhost:50051 list
For a TLS listener whose certificate chains to a trusted CA, omit -plaintext:
grpcurl localhost:50051 list
A cleartext call sent to a TLS listener, or a TLS call sent to a cleartext listener, normally fails before service discovery. Reflection settings cannot repair a transport mismatch.
2. Discover the schema or provide it locally
When reflection is enabled, list services and describe the method you intend to call:
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext localhost:50051 describe example.v1.ExampleService
grpcurl -plaintext localhost:50051 describe example.v1.ExampleService.GetItem
When reflection is disabled, provide the proto source and its import path:
grpcurl \
-plaintext \
-import-path ./protos \
-proto example/v1/service.proto \
-d '{"id":"test-item"}' \
localhost:50051 \
example.v1.ExampleService/GetItem
Proto imports must resolve from the supplied import directories. Missing imports, incompatible descriptors, and an incorrect package name are local schema problems. Resolve them before adding the tunnel.
3. Invoke a small unary method
grpcurl \
-plaintext \
-d '{"id":"test-item"}' \
localhost:50051 \
example.v1.ExampleService/GetItem
grpcurl options must appear before the target address and method name. If the application requires metadata, add only the headers documented by the application:
grpcurl \
-plaintext \
-H 'authorization: Bearer <REDACTED>' \
-d '{"id":"test-item"}' \
localhost:50051 \
example.v1.ExampleService/GetItem
An Unauthenticated or PermissionDenied result does not necessarily indicate a broken network path. It often proves that the request reached a gRPC-aware service capable of returning an application-level status.
4. Add stable diagnostic flags
Current official grpcurl builds expose -v for verbose output and -vv for more detailed verbose output. Use -v for ordinary comparisons and reserve -vv for deeper transport diagnosis because verbose captures can include metadata that requires redaction.
grpcurl \
-v \
-plaintext \
-d '{"id":"test-item"}' \
localhost:50051 \
example.v1.ExampleService/GetItem
Current builds also provide -connect-timeout for the connection-establishment limit and -max-time for the maximum total command duration. The values are expressed in seconds and may be fractional. Choose values appropriate to the service rather than copying these diagnostic examples into production automation unchanged:
grpcurl \
-v \
-plaintext \
-connect-timeout 10 \
-max-time 60 \
-d '{"id":"test-item"}' \
localhost:50051 \
example.v1.ExampleService/GetItem
Record whether the call connected, how long the first response took, how many messages arrived, whether the input side closed, and which final gRPC status grpcurl reported.
A tunnel cannot repair an incorrect method name, malformed JSON, missing protobuf imports, rejected credentials, disabled reflection, or a service that is not listening. Establish at least one successful local application RPC before creating the public path.
Configure a Localtonet TCP tunnel for the diagnostic
This tutorial deliberately uses the TCP tunnel family. A Localtonet TCP tunnel points to a local IP address and port and provides a public host and port while it is running. That makes it the narrowly scoped candidate for comparing a native gRPC listener through a raw port path without making unverified claims about every HTTP-aware tunnel configuration.
The supplied first-party Localtonet evidence does not document a tested matrix proving native HTTP/2 negotiation, bidirectional streaming, TLS termination behavior, authority routing, and gRPC trailer propagation for every HTTP/s, TLS, or TCP configuration. No path can therefore be presented here as universally confirmed for every deployment. This guide uses TCP as the selected diagnostic configuration and requires the grpcurl tests below to prove those properties for your service. HTTP/s and TLS tunnel families are not setup alternatives in this tutorial.
The maintained Localtonet workflow confirms the following sequence for a local IP and port tunnel. Account-specific fields, available relays, and plan capabilities can vary, so use the values shown in the current dashboard. The Localtonet documentation is the current first-party entry point for tunnel documentation.
Install and run the Localtonet client
Run our client on the machine hosting the gRPC service or on a device that can reach the listener over the local network. The client establishes an outbound connection to our relay, so the normal tunnel workflow does not require inbound router port forwarding, firewall changes, VPN setup, or a public IP address.
Authenticate or select the client device
Use the device-specific authentication token through the supported client and dashboard workflow. Tokens identify client devices and must be treated as secrets. Never add one to a grpcurl command, screenshot, repository, issue report, or shared diagnostic transcript.
Select an available relay server
Choose a server or region from the values currently available to your account. Do not copy a server code from another account or an old guide because available values can vary by plan, client version, region, or deployment.
Create the TCP tunnel with the verified local target
Select the TCP tunnel family and enter the local IP address and port that produced the successful local grpcurl call. If the Localtonet client runs on a different machine, 127.0.0.1 refers to that client machine, not automatically to the separate server. Use an address the selected client device can actually reach.
Start the tunnel
Creating the tunnel does not start it. Use the Start button and confirm that the selected client remains connected. The public endpoint is available only while that client is connected and the tunnel is running.
Record the assigned public host and port
Copy both values exactly from the running tunnel. grpcurl expects a host:port target, not an https:// URL. Keep the assigned hostname because replacing it with an IP address can change DNS behavior, certificate validation, TLS server identity, and HTTP/2 authority.
A TCP tunnel is not a substitute for TLS or application authorization. Match grpcurl's public-side TLS mode to the actual end-to-end service design. If the local listener is cleartext and the TCP path presents that listener unchanged to the public client, the public grpcurl call must use -plaintext. If the listener uses TLS, use TLS and validate the certificate presented through the public connection.
Repeat the baseline against the public host and port
Run the public test from a genuinely external network or device when possible. A same-host test remains useful, but an external client better represents the path that remote callers will use.
Test the public cleartext target
If the selected end-to-end design intentionally exposes the cleartext gRPC listener through TCP, use:
grpcurl \
-v \
-plaintext \
-connect-timeout 10 \
-max-time 60 \
public.example.invalid:12345 \
list
The hostname and port are intentionally nonfunctional placeholders. Substitute the exact host and port assigned to the running tunnel.
Test the public TLS target
If the gRPC listener expects TLS and its certificate is valid for the public identity:
grpcurl \
-v \
-connect-timeout 10 \
-max-time 60 \
public.example.invalid:12345 \
list
For a private certificate authority, provide the trusted CA certificate:
grpcurl \
-v \
-cacert ./certificates/ca.crt \
-connect-timeout 10 \
-max-time 60 \
public.example.invalid:12345 \
list
For mutual TLS, also provide the client certificate and private key:
grpcurl \
-v \
-cacert ./certificates/ca.crt \
-cert ./certificates/client.crt \
-key ./certificates/client.key \
-connect-timeout 10 \
-max-time 60 \
public.example.invalid:12345 \
list
Set authority and TLS server identity explicitly
In current official grpcurl builds, -authority sets the HTTP/2 :authority value. When TLS is used, grpcurl also uses that authoritative name for server certificate verification. This is the stable flag to use when the connection destination and intended service identity differ:
grpcurl \
-v \
-authority grpc.service.example \
-cacert ./certificates/ca.crt \
-connect-timeout 10 \
-max-time 60 \
public.example.invalid:12345 \
example.v1.ExampleService/GetItem
Do not assume that grpcurl provides an independent TLS server-name flag in every release. In the current official interface, -authority covers the authoritative HTTP/2 name and TLS certificate name used by this diagnostic. If you run an older packaged build, verify its help output and record the version rather than substituting an unverified flag from a third-party cheatsheet.
Avoid replacing the assigned hostname with a relay IP merely to test reachability. That can alter DNS resolution, certificate hostname validation, TLS server-name behavior, and HTTP/2 routing at the same time. It creates a different test rather than isolating one variable.
Repeat the unary method
grpcurl \
-v \
-connect-timeout 10 \
-max-time 60 \
-d '{"id":"test-item"}' \
public.example.invalid:12345 \
example.v1.ExampleService/GetItem
Add -plaintext only when the public connection intentionally has no TLS. Keep the method, request body, descriptors, and application metadata identical to the local baseline.
Use insecure verification only as a comparison
grpcurl's -insecure option keeps TLS enabled but disables normal certificate verification. It can help distinguish a reachable TLS path from a hostname or trust-chain defect:
grpcurl \
-insecure \
-v \
-d '{"id":"test-item"}' \
public.example.invalid:12345 \
example.v1.ExampleService/GetItem
-insecure
If a call works only with verification disabled, the transport may be reachable while certificate trust or hostname validation remains incorrect. Use the intended hostname, install the correct trusted CA, and repair the certificate configuration instead of retaining -insecure.
What the TCP validation must prove
A successful unary response is necessary but not sufficient for this tutorial's compatibility decision. The public test must prove the properties your application actually requires:
- The client establishes the expected cleartext HTTP/2 or TLS connection.
- TLS certificate verification succeeds with the intended authority when TLS is used.
- The correct service and method receive the call.
- Required application metadata reaches the service and authorization behaves as expected.
- The required unary and streaming messages arrive without unexplained buffering.
- Client half-close and server completion behavior match the local baseline.
- grpcurl receives and reports the final gRPC status.
If any required property fails, do not describe the configuration as compatible merely because the port is reachable or a unary health method works.
Test each required streaming pattern deliberately
After the public unary method succeeds, test the streaming mode used by the application. Unary success does not prove long-lived streams, multiple request messages, client half-close behavior, interactive exchange, or final trailer delivery.
Server-streaming RPC
grpcurl \
-v \
-max-time 300 \
-d '{"topic":"diagnostic"}' \
public.example.invalid:12345 \
example.v1.StreamService/Watch
Add -plaintext if the public connection is intentionally cleartext. Determine how the method is supposed to finish. A finite stream should send its expected messages and return a final status. A watch-style stream may remain active until the client cancels it, a deadline expires, or an application event ends it.
Compare time to first message, spacing between messages, number of messages, stream duration, and final status with the local call. If the server emits messages periodically but the remote client receives them in a batch, investigate buffering in the actual application and network path.
Client-streaming RPC
The official grpcurl interface uses -d @ to read request messages from standard input. A pipeline provides repeatable input and closes automatically at end-of-file:
printf '%s\n' \
'{"value":"first"}' \
'{"value":"second"}' \
'{"value":"third"}' |
grpcurl \
-v \
-max-time 300 \
-d @ \
public.example.invalid:12345 \
example.v1.StreamService/Upload
End-of-file is significant. It tells grpcurl that no more client messages will be sent. A server that waits for the client half-close may not produce its response until standard input closes. If the command appears to wait forever during an interactive test, verify that you completed each JSON object and sent the terminal's end-of-file action.
Bidirectional-streaming RPC
grpcurl \
-vv \
-max-time 300 \
-d @ \
public.example.invalid:12345 \
example.v1.StreamService/Chat
grpcurl reads request objects from standard input while displaying server responses. Bidirectional streams do not necessarily alternate requests and responses. The server may respond immediately, wait for several inputs, emit asynchronous events, or wait for the client sending side to close.
Use -vv only when the additional output is needed, and redact sensitive metadata before retaining the transcript.
Treat deadlines as a controlled variable
-connect-timeout limits how long grpcurl waits to establish the connection. -max-time limits the total invocation time. They answer different questions. A connection timeout does not diagnose a stream that establishes successfully and fails later.
Run one test with a realistic application limit and another with a deliberately generous diagnostic limit. If only the longer test succeeds, identify whether time is spent during connection establishment, service processing, first-message delivery, an idle interval, or stream completion. Raising every timeout without locating the expiring layer can conceal the real failure.
Check the final result after visible messages
For every stream, capture the command's final output and exit status. A server can send valid messages and later return Cancelled, DeadlineExceeded, Internal, or another non-success status. A path that loses the final trailers has not demonstrated complete gRPC compatibility.
Troubleshoot failures by the first broken checkpoint
| Observed symptom | Likely diagnostic area | Next check |
|---|---|---|
| Connection refused locally | Service process, listener address, or port | Confirm the process is running and verify its real bind address and port. |
| Local TLS handshake fails | TLS mode, trust chain, or certificate name | Confirm whether the listener expects TLS and validate its certificate configuration. |
Local list fails but a descriptor-based method works |
Reflection | Treat reflection as disabled or restricted and continue with verified local descriptors. |
| Local call succeeds but public connection times out | Tunnel lifecycle or public target | Confirm that the client is connected, the tunnel is started, and the public host and port are exact. |
| Public connection succeeds but the service is unknown | Wrong target port, method path, or application instance | Compare the fully qualified method and verify that the TCP target is the same listener tested locally. |
TLS succeeds only with -insecure |
Certificate trust or hostname validation | Use the intended authority and install the correct trusted CA. |
Unauthenticated or PermissionDenied |
Application authorization | Verify the credential, scope, audience, expiry, and required metadata. |
| Unary succeeds but a stream ends early | Deadline, cancellation, timeout, or stream handling | Measure the failure interval and compare client, server, and application limits. |
| Responses arrive in a batch | Application or path buffering | Compare grpcurl timing with timestamped server logs and verify that the server emits each message. |
| Client-streaming command never returns | Input not closed or invalid request sequence | Use a fixed pipeline, valid JSON objects, and a predictable end-of-file. |
| Messages arrive but completion fails | Application error, connection closure, or missing trailers | Use verbose output and compare the final local and public gRPC statuses. |
Reflection fails only through the public path
Verify reflection locally with the same TLS mode, then invoke a known method publicly using local proto files. If the method succeeds while public reflection fails, the path can carry that tested RPC and the problem is narrower than total gRPC failure.
Confirm whether reflection is intentionally available in the public environment. Do not weaken production controls solely to make grpcurl list convenient.
The public target returns non-gRPC data
A TCP connection may reach the wrong local listener. If grpcurl receives behavior resembling a web page, redirect, management interface, or ordinary HTTP response, verify the local target port. A browser-accessible health page on another port does not prove that the native gRPC listener is correctly targeted.
The certificate is valid for a hostname, but the test uses an IP
Connect using the assigned public hostname whenever that is the intended identity. An IP-based test can fail certificate hostname validation and change the authority sent to the service. When the intended authority differs from the connection destination, use the current -authority flag rather than disabling verification.
The method is reported as unimplemented
Verify the exact package, service, and method path. Confirm that the public target reaches the same listener and application version as the local baseline. A valid Unimplemented result is useful evidence because it differs from a failure to establish a gRPC connection.
Only long-lived streams fail
Measure the interval from connection establishment to failure. A stream that consistently ends after the same duration often indicates a deadline, idle limit, or application timeout. Compare that interval with grpcurl's -max-time, the application's deadline behavior, and server-side limits.
Change one limit at a time. First determine whether the client cancels the RPC, the server closes it, traffic stops while the stream remains open, or final trailers disappear.
Responses are delayed or buffered
Compare the stream with timestamped application logs. Make sure the server framework actually emits each response when expected. If server logs show periodic emission but the public client receives messages together, document the timing and identify the layer accumulating data before changing unrelated timeout settings.
The client-streaming method waits indefinitely
Confirm that every input object is valid for the protobuf descriptor and that standard input reaches end-of-file. A server can legitimately wait because the client has not closed its sending side. A fixed pipeline is usually more repeatable than manually entering messages.
The tunnel exists but is unavailable
Check lifecycle state before changing gRPC settings. Creating a Localtonet tunnel does not start it. The selected client must remain connected, and the tunnel must be running. Also verify that the configured target is reachable from the Localtonet client device itself.
Operate a remotely reachable gRPC endpoint safely
A successful test creates a publicly reachable path to the selected local service. Treat that as an exposure decision rather than only a connectivity experiment.
- Require application authentication and authorization for non-public RPCs.
- Use least-privilege test identities and short-lived credentials where your application supports them.
- Keep reflection disabled or restricted when public schema discovery is unnecessary.
- Use certificate verification and the intended trusted CA during normal TLS operation.
- Protect mutual TLS private keys and never upload them to repositories or issue trackers.
- Avoid destructive RPCs and production data during connectivity diagnostics.
- Redact authorization metadata, personal data, request payloads, and private endpoint details from logs.
- Use deliberate connection and execution limits so abandoned tests do not remain active indefinitely.
- Stop or delete the tunnel when remote access is no longer required.
Our client establishes an outbound connection to a Localtonet relay, so the normal tunnel workflow does not require inbound router port forwarding, firewall changes, VPN setup, or a public IP address. That connectivity model does not replace service-level security. The exposed application remains responsible for deciding who may invoke each method.
Reflection can disclose service names, methods, and message schemas. If remote reflection is required for a controlled diagnostic, apply the same authentication and exposure review used for the application endpoint. Remove unnecessary public access after the test.
Review -v and -vv captures before saving or sharing them. Remove bearer tokens, cookies, client identities, private hostnames, request data, and response data that should not leave the authorized diagnostic environment.
Use this final local-to-public checklist
- Confirm that the gRPC process is running and identify its actual bind address and port.
- Determine whether the local listener expects TLS or cleartext HTTP/2.
- Install grpcurl from an official project path and record the installed version.
- Obtain the service descriptors through authorized reflection, proto source files, or a protoset.
- Complete one small unary RPC locally.
- Record the method, request, metadata, TLS mode, authority, timing, response, and final status.
- Run the required streaming method locally and document how it normally completes.
- Run the Localtonet client on a device that can reach the verified listener.
- Select the device-specific token and an available relay in the current dashboard.
- Create a TCP tunnel that targets the verified local IP address and port.
- Start the tunnel and confirm that the selected client remains connected.
- Copy the assigned public host and port exactly.
- Repeat reflection or descriptor-based discovery against the public target.
- Repeat the unary RPC without changing unrelated application inputs.
- Use
-authorityif the intended HTTP/2 and TLS identity differs from the connection destination. - Use
-connect-timeoutand-max-timeto separate connection failures from total invocation limits. - Test the required server-streaming, client-streaming, or bidirectional-streaming method.
- Compare message timing, end-of-file handling, cancellation, and the final gRPC status.
- Do not claim compatibility unless the required HTTP/2, TLS, streaming, authority, and trailer behavior succeeds.
- Redact diagnostic output and stop or delete the tunnel when testing is complete.
Frequently asked questions
Can regular curl replace grpcurl for native gRPC testing?
Not for the workflow in this guide. grpcurl understands gRPC service descriptors, converts JSON into protobuf messages, invokes service methods, supports streaming, and displays decoded responses and final gRPC statuses. A basic HTTP request does not provide an equivalent native gRPC test.
Does grpcurl require server reflection?
No. Reflection is convenient for runtime discovery, but grpcurl can also use local .proto files or compiled protoset files. A reflection failure does not prove that application RPCs are unavailable.
Does -plaintext make grpcurl use HTTP/1.1?
No. It disables TLS for the connection. Native gRPC still uses HTTP/2 semantics. The option does not convert a gRPC service into an HTTP/1.1 API.
Why does this guide use a Localtonet TCP tunnel?
The tutorial is intentionally narrowed to the TCP tunnel family, which maps a local IP address and port to a public host and port. The available first-party evidence does not establish a universal native gRPC compatibility matrix for all HTTP/s, TLS, and TCP configurations. The required grpcurl tests must still verify HTTP/2, TLS, authority, streaming, and final trailers for the actual service.
Which grpcurl flag sets the HTTP/2 authority and TLS certificate name?
Current official grpcurl builds use -authority for the HTTP/2 :authority value. When TLS is enabled, that authoritative name is also used for certificate verification. Record your grpcurl version when reproducing a diagnostic because older packaged builds can differ.
What is the difference between -connect-timeout and -max-time?
-connect-timeout limits connection establishment. -max-time limits the total grpcurl invocation. A stream can connect within the first limit and later be cancelled by the second, so record which limit expired.
Why does a streaming grpcurl command keep running?
The method may be designed to remain active. A server-streaming watch can wait for future events, while a client-streaming or bidirectional method may wait for more standard input. Review the method contract, close input with end-of-file when appropriate, and use a deliberate -max-time for bounded diagnostics.
Is it safe to leave -insecure enabled?
No. Use it only as a temporary comparison. It disables certificate verification and can conceal an incorrect hostname or trust chain. Normal operation should use the intended authority and a certificate chain trusted by the client.
Does creating a Localtonet tunnel make it immediately available?
No. The tunnel must be started, and its selected client device must remain connected. The endpoint is available only while the client is connected and the tunnel is running. Stop or delete it when remote access is no longer required.
Test your gRPC service through a controlled TCP endpoint
Establish a successful local grpcurl baseline, start a Localtonet TCP tunnel to the verified listener, and prove the public RPC one protocol checkpoint at a time.
Get Started Free β