# How to Run Gin on Unix Sockets: Complete Guide with Examples

> Learn how to run Gin on Unix sockets with this complete guide. Discover efficient inter-process communication for your Gin applications and optimize performance.

- Repository: [Gin-Gonic/gin](https://github.com/gin-gonic/gin)
- Tags: how-to-guide
- Published: 2026-02-27

---

**Gin serves HTTP over Unix domain sockets via `router.RunUnix(file)`, which creates a `net.Listener` using `net.Listen("unix", path)`, automatically manages the socket file lifecycle with `defer os.Remove(file)`, and blocks until the server stops or encounters an error.**

Running Gin on Unix sockets provides a lightweight, secure IPC mechanism for local process communication, eliminating TCP overhead and port management. The gin-gonic/gin repository provides first-class support for Unix domain sockets through the `RunUnix` method, available both on individual engine instances and as a package-level helper. This approach is ideal for microservices behind reverse proxies, containerized applications, or systemd socket-activated services.

## How RunUnix Works Under the Hood

### The Engine Implementation in [`gin.go`](https://github.com/gin-gonic/gin/blob/main/gin.go)

The core implementation resides in [`gin.go`](https://github.com/gin-gonic/gin/blob/main/gin.go) within the `Engine.RunUnix` method. According to the gin-gonic/gin source code, the method performs four critical operations:

1. **Creates the socket listener** using `net.Listen("unix", file)` to establish a file-based socket
2. **Validates trusted proxy configuration** using the same logic as other `Run*` helpers
3. **Logs the startup** with the debug message: `Listening and serving HTTP on unix:/%s`
4. **Serves traffic** by passing the listener to `http.Server.Serve(listener)`, which blocks until shutdown

The implementation leverages Go's standard `net` package to handle the Unix socket creation, ensuring compatibility with POSIX systems while maintaining Gin's familiar API surface.

### Socket Lifecycle Management

Gin automatically manages the Unix socket file lifecycle to prevent stale socket accumulation. In [`gin.go`](https://github.com/gin-gonic/gin/blob/main/gin.go), the method executes `defer os.Remove(file)` immediately after creating the listener, ensuring the socket file is deleted when `RunUnix` returns—whether through normal shutdown, error, or process termination. This deferred cleanup runs after `server.Serve(listener)` unblocks, providing automatic resource management without manual intervention.

## Basic Implementation: Running Gin on a Unix Socket

To run your Gin application on a Unix domain socket, invoke `RunUnix` on your router instance with the absolute path to the socket file. The path must be writable by the process and should not already exist.

```go
package main

import (
	"log"

	"github.com/gin-gonic/gin"
)

func main() {
	// Initialize router (gin.Default(), gin.New(), or custom middleware chains)
	r := gin.Default()

	// Define routes as usual
	r.GET("/", func(c *gin.Context) {
		c.String(200, "Hello from Unix socket!")
	})

	r.GET("/health", func(c *gin.Context) {
		c.JSON(200, gin.H{"status": "healthy"})
	})

	// Unix socket path - typically in /tmp/, /run/, or application-specific directories
	const socketPath = "/tmp/gin.sock"

	// Start blocking server on Unix socket
	if err := r.RunUnix(socketPath); err != nil {
		log.Fatalf("failed to run Gin on Unix socket: %v", err)
	}
}

```

When this executes, Gin binds to the filesystem socket rather than a TCP port, making the application accessible only to local processes with appropriate filesystem permissions.

## Alternative: Using the Package-Level Helper

For applications using the default Gin engine without custom middleware configuration, the package-level `gin.RunUnix` in [`ginS/gins.go`](https://github.com/gin-gonic/gin/blob/main/ginS/gins.go) provides a concise wrapper. This helper forwards the call to the default engine instance, reducing boilerplate for simple services.

```go
package main

import (
	"log"

	"github.com/gin-gonic/gin"
)

func main() {
	// Uses gin.Default() internally via ginS/gins.go
	if err := gin.RunUnix("/var/run/myapp.sock"); err != nil {
		log.Fatalf("server error: %v", err)
	}
}

```

The wrapper in [`ginS/gins.go`](https://github.com/gin-gonic/gin/blob/main/ginS/gins.go) (line 150) simply delegates to `defaultEngine.RunUnix`, making it functionally equivalent to creating a default router manually but requiring less code.

## Testing and Verifying Unix Socket Connections

After starting your Gin application, verify the socket creation and test HTTP communication using standard Unix tools. The socket appears as a regular file with special permissions indicating it is a socket.

```bash

# Verify the socket file exists with correct type

ls -l /tmp/gin.sock

# Output: srwxr-xr-x 1 user group 0 Jan 15 10:30 /tmp/gin.sock

# Test using curl's Unix socket support

curl --unix-socket /tmp/gin.sock http://localhost/

# Expected: Hello from Unix socket!

# Send requests to specific routes

curl --unix-socket /tmp/gin.sock http://localhost/health

```

For integration testing within your Go test suite, the repository provides patterns in [`gin_integration_test.go`](https://github.com/gin-gonic/gin/blob/main/gin_integration_test.go) (line 95), demonstrating how to start temporary Unix sockets during tests and handle cleanup automatically.

## Production Considerations

When deploying Gin applications with Unix sockets in production environments, address these critical operational factors:

**File Permissions** - The socket file inherits the umask and permissions of the creating process. Ensure the socket is readable/writable by the connecting processes (e.g., nginx, another container, or a different user). You may need to adjust permissions post-creation or run the service under specific user/group contexts.

**Stale Socket Files** - If the socket file already exists when `RunUnix` starts, `net.Listen` returns an error and Gin fails to start. Implement pre-flight checks to remove stale sockets from unclean shutdowns, or rely on Gin's automatic cleanup during graceful shutdowns.

**Graceful Shutdown** - Because Gin removes the socket file on exit through the deferred `os.Remove(file)` call, ensure your application handles `SIGTERM` and `SIGINT` signals properly. A clean shutdown preserves the socket cleanup behavior, while hard kills (`SIGKILL`) may leave stale files requiring manual removal before restart.

**Systemd Integration** - For systemd socket activation, ensure your service unit specifies the socket file path consistently between the systemd `.socket` unit and your Gin application configuration.

## Summary

- **`RunUnix` in [`gin.go`](https://github.com/gin-gonic/gin/blob/main/gin.go)** creates Unix domain sockets using `net.Listen("unix", path)` and manages the full server lifecycle
- **Automatic cleanup** via `defer os.Remove(file)` ensures socket files are deleted when the server stops
- **Two API entry points** exist: `router.RunUnix` for custom engines and `gin.RunUnix` in [`ginS/gins.go`](https://github.com/gin-gonic/gin/blob/main/ginS/gins.go) for default configurations
- **Local-only access** provides security benefits over TCP ports for inter-process communication on the same host
- **Integration tests** in [`gin_integration_test.go`](https://github.com/gin-gonic/gin/blob/main/gin_integration_test.go) demonstrate production-ready patterns for testing Unix socket servers

## Frequently Asked Questions

### What happens if the Unix socket file already exists?

Gin will fail to start with an error from the underlying `net.Listen("unix", path)` call. You must manually remove the existing socket file before starting the server, or ensure a previous instance performed a clean shutdown where Gin's deferred `os.Remove(file)` executed properly.

### How do I control permissions on the created Unix socket?

The socket inherits the process umask and effective user/group. To restrict access, configure your process to run under specific user contexts or adjust umask before calling `RunUnix`. Unlike TCP sockets, Unix domain sockets use filesystem permissions, allowing granular access control via standard `chmod` and ownership changes.

### Can I use Unix sockets with systemd socket activation?

Yes, though you must adapt the pattern slightly. Instead of having Gin create the socket, systemd passes the file descriptor. You would use `net.Listener` from systemd's socket activation and pass it to `http.Server.Serve()` manually, rather than using `RunUnix` directly, since `RunUnix` always creates a new listener via `net.Listen`.

### Is there a performance difference between Unix sockets and TCP localhost?

Unix sockets typically offer **10-20% lower latency** and **higher throughput** than TCP localhost connections because they bypass the entire TCP/IP stack, eliminating packet encapsulation, checksums, and network buffer management. For high-throughput local services, Unix sockets provide measurable efficiency gains with zero network overhead.