# How Socket Forwarding Works for Publishing Unix Sockets from Container to Host

> Learn how container runtimes declaratively manage Unix socket forwarding from container to host using UnixSocketConfiguration objects, not generic SocketForwarder.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: internals
- Published: 2026-06-13

---

**Unix socket forwarding from container to host is handled declaratively by the container runtime through `UnixSocketConfiguration` objects, not by the generic `SocketForwarder` used for TCP/UDP ports.**

In the `apple/container` repository, publishing Unix domain sockets from a container to the host operates through a configuration-driven mechanism that establishes a direct bridge between the container's socket file and a host-side endpoint. Unlike network port forwarding, which relies on active packet forwarding, Unix socket publishing leverages the container runtime's static configuration to create bind-mounted socket nodes that persist for the container's lifecycle.

## Configuration Parsing in RuntimeService

The socket forwarding process begins when the container engine reads the configuration. In [`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift), the `configureContainer` method processes entries from the `publishedSockets` array between lines 1017 and 1030. Each entry transforms into a `UnixSocketConfiguration` where the container path serves as the **source** and the host path serves as the **destination**.

### Direction Flag for Flow Control

The `direction` parameter determines socket accessibility. Setting `direction: .outOf` exposes the socket from the container to the host, enabling external processes to connect to services running inside the container. Conversely, `.into` allows the container to consume host-provided sockets, such as SSH authentication sockets.

## Container Configuration Injection

After parsing, the `UnixSocketConfiguration` objects append to `czConfig.sockets`—the low-level container configuration array. When the `LinuxContainer` instance initializes, this configuration passes to the underlying Containerization framework. The framework creates the host-side socket node, applies the requested POSIX permissions, and binds the container and host endpoints together.

## Lifecycle Management

Because sockets are declared in static configuration, the runtime establishes them during the VM bootstrap phase and automatically tears them down via `cleanUpContainer` when the container stops. This design eliminates the need for separate forwarding tasks; the socket operates as a standard file descriptor accessible to both sides without active proxying.

## Configuration Examples

### JSON Configuration Structure

Define published sockets in the container configuration:

```json
{
  "id": "my-app",
  "publishedSockets": [
    {
      "containerPath": "/run/my-app.sock",
      "hostPath": "/tmp/my-app.sock",
      "permissions": "rw"
    }
  ]
}

```

### Swift Implementation

The following Swift code mirrors the implementation in `RuntimeService.configureContainer`:

```swift
let socketConfig = UnixSocketConfiguration(
    source: URL(filePath: publishedSocket.containerPath.string),
    destination: URL(filePath: publishedSocket.hostPath.string),
    permissions: publishedSocket.permissions,
    direction: .outOf
)
czConfig.sockets.append(socketConfig)

```

### Command-Line Usage

Use the `--publish-socket` flag when running containers:

```bash
container run \
    --publish-socket /run/my-app.sock:/tmp/my-app.sock \
    my-image:latest

```

The CLI parser in [`ContainerCLI.swift`](https://github.com/apple/container/blob/main/ContainerCLI.swift) populates the `publishedSockets` array, triggering the configuration flow described above.

## Key Implementation Files

- **[`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift)**: Contains the `configureContainer` method that parses `publishedSockets` and constructs `UnixSocketConfiguration` objects (lines 1017-1030).

- **[`Sources/SocketForwarder/SocketForwarder.swift`](https://github.com/apple/container/blob/main/Sources/SocketForwarder/SocketForwarder.swift)**: Defines the generic forwarding protocol used for TCP/UDP port publishing; **not** involved in Unix socket publishing.

- **[`Sources/CLI/ContainerCLI.swift`](https://github.com/apple/container/blob/main/Sources/CLI/ContainerCLI.swift)**: Handles the `--publish-socket` command-line option and configuration marshalling.

- **[`External/Containerization/UnixSocketConfiguration.swift`](https://github.com/apple/container/blob/main/External/Containerization/UnixSocketConfiguration.swift)**: Defines the low-level configuration type that the container runtime uses to establish host-side socket nodes.

## Summary

- Unix socket publishing uses declarative configuration rather than active forwarding.
- The `RuntimeService.configureContainer` method transforms `publishedSockets` entries into `UnixSocketConfiguration` objects with `direction: .outOf`.
- Sockets are injected into `czConfig.sockets` and processed by the `LinuxContainer` initialization.
- The Containerization framework handles lifecycle management automatically during bootstrap and cleanup.
- Unlike TCP/UDP port forwarding, this mechanism does not use the `SocketForwarder` class.

## Frequently Asked Questions

### Does Unix socket publishing use the same SocketForwarder as TCP/UDP ports?

No. According to the `apple/container` source code, Unix socket publishing is performed entirely by the container runtime's configuration system. The `SocketForwarder` class defined in [`SocketForwarder.swift`](https://github.com/apple/container/blob/main/SocketForwarder.swift) handles TCP/UDP port forwarding, while Unix sockets rely on `UnixSocketConfiguration` objects processed during container initialization.

### What is the difference between direction `.outOf` and `.into`?

The `direction` parameter in `UnixSocketConfiguration` controls socket accessibility. The `.outOf` flag exposes sockets from the container to the host, allowing host processes to connect to container services. The `.into` flag enables the container to access host-provided sockets, such as SSH authentication sockets.

### When are the host-side sockets created and destroyed?

Host-side sockets are established during the container's bootstrap phase when the `LinuxContainer` initializes using the `czConfig.sockets` configuration. They are automatically cleaned up via the `cleanUpContainer` method when the container stops, requiring no manual intervention.

### How do permissions work for published Unix sockets?

The `permissions` field in the socket configuration accepts POSIX-style permission strings (e.g., `"rw"`). These permissions are applied to the host-side socket node when the Containerization framework creates it, ensuring proper access control between host processes and the container.