Cloudflare's command-line tool and networking daemon written in Go. Production-grade tunneling and network connectivity services used by millions of developers and organizations worldwide.
# Full development check (run before any commit)
make test lint
# Build for current platform
make cloudflared
# Run all unit tests with coverage
make test
make cover
# Run specific test
go test -run TestFunctionName ./path/to/package
# Run tests with race detection
go test -race ./...# Linux
TARGET_OS=linux TARGET_ARCH=amd64 make cloudflared
# Windows
TARGET_OS=windows TARGET_ARCH=amd64 make cloudflared
# macOS ARM64
TARGET_OS=darwin TARGET_ARCH=arm64 make cloudflared
# FIPS compliant build
FIPS=true make cloudflared# Run linter (38+ enabled linters)
make lint
# Auto-fix formatting
make fmt
gofmt -w .
goimports -w .
# Security scanning
make vet
# Component tests (Python integration tests)
cd component-tests && python -m pytest test_file.py::test_function_nameNotes on linting:
.golangci.yamlis configured withnew-from-revandwhole-files: true. Touching a file triggers linting of the ENTIRE file, not just the changed hunks. Expect to fix pre-existing issues in files you modify, or add targeted// nolint: <linter>comments with a short justification.- Prefer
defer func() { _ = resource.Close() }()overdefer resource.Close()forio.Closervalues whose error truly does not matter — this satisfieserrcheckwithout hiding real failures elsewhere.
- Use meaningful package names that reflect functionality
- Package names should be lowercase, single words when possible
- Avoid generic names like
util,common,helper
crypto/: Single source of truth for TLS curve preferences and other cryptographic primitives shared by every edge-facing transport. Import ascfdcrypto "github.com/cloudflare/cloudflared/crypto"to avoid colliding with the standard library'scryptopackage. Do NOT duplicate TLS curve or cipher selection logic in other packages.tlsconfig/: Builds the base*tls.Configused for edge connections (CreateTunnelConfig) and loads origin/CA pools. Curve selection is intentionally NOT set here; it is applied per-connection from thecrypto/package so the same config can be cloned and reused across protocols.features/: Runtime feature flags includingPostQuantumMode(PostQuantumPrefer= default,PostQuantumStrict=--post-quantum).fips/: Build-tag driven FIPS detection. Onlyfips.IsFipsEnabled()is exposed; never branch onfipsEnabledinside a function if the two branches return the same value.
// Good: Clear purpose, proper error handling
func (c *Connection) HandleRequest(ctx context.Context, req *http.Request) error {
if req == nil {
return errors.New("request cannot be nil")
}
// Implementation...
return nil
}- Always handle errors explicitly, never ignore them
- Use
fmt.Errorffor error wrapping - Create meaningful error messages with context
- Use error variables for common errors
// Good error handling patterns
if err != nil {
return fmt.Errorf("failed to process connection: %w", err)
}- Use
github.com/rs/zerologfor structured logging - Include relevant context fields
- Use appropriate log levels (Debug, Info, Warn, Error)
logger.Info().
Str("tunnelID", tunnel.ID).
Int("connIndex", connIndex).
Msg("Connection established")- Use
github.com/stretchr/testifyfor assertions - Test files end with
_test.go - Use table-driven tests for multiple scenarios
- Always use
t.Parallel()for parallel-safe tests - Use meaningful test names that describe behavior
func TestMetricsListenerCreation(t *testing.T) {
t.Parallel()
// Test implementation
assert.Equal(t, expected, actual)
require.NoError(t, err)
}const (
MaxGracePeriod = time.Minute * 3
MaxConcurrentStreams = math.MaxUint32
LogFieldConnIndex = "connIndex"
)
var (
// Group related variables
switchingProtocolText = fmt.Sprintf("%d %s", http.StatusSwitchingProtocols, http.StatusText(http.StatusSwitchingProtocols))
flushableContentTypes = []string{sseContentType, grpcContentType, sseJsonContentType}
)- Define interfaces close to their usage
- Keep interfaces small and focused
- Use descriptive names for complex types
type TunnelConnection interface {
Serve(ctx context.Context) error
}
type TunnelProperties struct {
Credentials Credentials
QuickTunnelUrl string
}- Always accept
context.Contextas first parameter for long-running operations - Respect context cancellation in loops and blocking operations
- Pass context through call chains
- Use channels for goroutine communication
- Protect shared state with mutexes
- Prefer
sync.RWMutexfor read-heavy workloads *tls.Configvalues stored in shared maps (e.g.TunnelConfig.EdgeTLSConfigs) must beClone()d before mutating per-connection fields likeCurvePreferencesorNextProtos. Writing through the shared pointer races with concurrent connection attempts.
- Per-connection TLS configuration for edge connections is built via
cfdcrypto.TLSConfigWithCurvePreferences(tlsConfig, pqMode). It clones the provided*tls.Configand setsCurvePreferencesbased onpqMode, so callers never need to clone or mutateCurvePreferencesthemselves. Do NOT reach for the package-privategetCurvePreferenceshelper; the exportedTLSConfigWithCurvePreferencesis the only supported entry point. - Two PQ modes are supported and apply identically to QUIC and HTTP/2:
PostQuantumPrefer(default):[X25519MLKEM768, P256Kyber768Draft00, CurveP256]PostQuantumStrict(--post-quantum):[X25519MLKEM768, P256Kyber768Draft00]
- FIPS and non-FIPS builds use the same curve list. Do NOT reintroduce a
fipsEnabledbranch in curve-selection code; if the two modes ever diverge, express the divergence insidecrypto/so call sites remain untouched. - HTTP/2 supports post-quantum handshakes. Never re-add a
PostQuantumStrict-based rejection to H2 code paths, and never force--post-quantumto select QUIC-only in protocol selection.
- Use structured configuration with validation
- Support both file-based and CLI flag configuration
- Provide sensible defaults
- Instrument code with Prometheus metrics
- Use OpenTelemetry for distributed tracing
- Include structured logging with relevant context
- Run
make test lintbefore any commit - Handle all errors explicitly with proper context
- Use
github.com/rs/zerologfor all logging - Add
t.Parallel()to all parallel-safe tests - Follow the import grouping conventions
- Use meaningful variable and function names
- Include context.Context for long-running operations
- Close resources in defer statements
- Adding new dependencies to go.mod
- Modifying CI/CD configuration files
- Changing build system or Makefile
- Modifying component test infrastructure
- Adding new linter rules or changing golangci-lint config
- Making breaking changes to public APIs
- Changing logging levels or structured logging fields
- Ignore errors without explicit handling (
_ = err) - Use generic package names (
util,helper,common) - Commit code that fails
make test lint - Use
fmt.Print*instead of structured logging - Modify vendor dependencies directly
- Commit secrets, credentials, or sensitive data
- Use deprecated or unsafe Go patterns
- Skip testing for new functionality
- Remove existing tests unless they're genuinely invalid
- Use Go modules (
go.mod) exclusively - Vendor dependencies for reproducible builds
- Keep dependencies up-to-date and secure
- Prefer standard library when possible
- Cloudflared uses a fork of quic-go always check release notes before bumping this dependency.
- FIPS compliance support available
- Vulnerability scanning integrated in CI
- Credential handling follows security best practices
- Network security with TLS/QUIC protocols
- Regular security audits and updates
- Post quantum encryption
- Graceful shutdown: Always implement proper cleanup
- Resource management: Close resources in defer statements
- Error propagation: Wrap errors with meaningful context
- Configuration validation: Validate inputs early
- Logging consistency: Use structured logging throughout
- Testing coverage: Aim for comprehensive test coverage
- Documentation: Comment exported functions and types
Remember: This is a mission-critical networking tool used in production by many organizations. Code quality, security, and reliability are paramount.