Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions server-guides/Sources/ServerGuides.docc/Documentation.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# ``ServerGuides``

## Topics

- <doc:packaging>
- <doc:deploying-static-binaries>
173 changes: 173 additions & 0 deletions server-guides/Sources/ServerGuides.docc/deploying-static-binaries.md
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So overall this tutorial looks great but I'm not sure we want to make this server specific? CLI tools especially work great with the static SDK

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see where you're going, however I'm not sure how we'd broadly like to reconcile initial goals of porting and updating the swift server guides into DocC and getting them published, specific to the server side use cases. I totally agree it's a fantastic possible mechanism to make easily-used executables that can run on linux or macOS (or other platforms, as long as they can run a Linux container).

I've got queued up to move the "getting started with Static Linux SDK" as it's own article - and it sounds like "Swift on Linux" is a worthwhile thing, @FranzBusch has made the same comments to me. So let me ask - does this article sound like it's wrong or doesn't fit here, because it's more aligned elsewhere or with something else, or are you thinking that we just need a broader scope for content that is "Swift on Linux" more generally?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, general guides for building Swift applications and another guide for building docker images makes sense. Neither of those should be tied to the Swift Server use-case since they are generally useful to many different use-cases.

Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Deploying Swift services as static binaries

Build fully self-contained Swift executables and deploy them
to minimal containers or directly to Linux machines.

## Overview

The Static Linux SDK produces Swift executables with no external dependencies —
not even the C library.
This lets you run the binary on any Linux machine regardless of distribution,
which opens deployment options that aren't possible with dynamically linked builds.

You can copy the binary into a `scratch` or distroless container image that contains nothing but your executable.
Or skip containers entirely and copy the binary to a virtual machine.
Either way, the result is the smallest possible deployment artifact with the smallest possible attack surface.

This article walks you through installing the SDK, building a static binary, and deploying it.

### Install the Static Linux SDK

The Static Linux SDK requires an open source Swift toolchain.
The toolchain bundled with Xcode doesn't support SDK-based cross-compilation.
Use `swiftly` to install an open source Swift toolchain, then install the Static Linux SDK for that toolchain.
Go to [swift.org](https://www.swift.org/install/) for the links and commands to install both.

Install the SDK with `swift sdk install`, providing the URL for your Swift version.
The command follows this form:

```bash
swift sdk install <url> --checksum <checksum>
```

After installation, verify the SDK is available:

```bash
swift sdk list
```

The output includes SDK names like `x86_64-swift-linux-musl`
and `aarch64-swift-linux-musl` that you use in build commands.

### Build a static binary

Build your service with the `--swift-sdk` flag,
specifying the target architecture:

```bash
swift build -c release --swift-sdk aarch64-swift-linux-musl
```

For x86_64 targets, use the corresponding SDK name:

```bash
swift build -c release --swift-sdk x86_64-swift-linux-musl
```

This produces a statically linked ELF binary in `.build/release/`
that you can copy to any Linux system and run directly.
The SDK uses [Musl](https://musl.libc.org) instead of Glibc
and statically links everything the executable needs —
including the Swift standard library, Foundation, and system libraries
like libcurl and libxml2.

> Note: Because Musl replaces Glibc,
> some packages that import C libraries need changes —
> for example, changing import lines from `Glibc` to `Musl`.
> The Swift standard library and Foundation handle this automatically.

### Deploy to a distroless container image

A distroless container image contains no operating system utilities —
no package manager, no shell, nothing but what you put in it.
This eliminates an entire class of potential vulnerabilities
because there are no extra programs an attacker could exploit.

Because the Static Linux SDK cross-compiles from your development machine,
you don't need a multi-stage Dockerfile with a Swift SDK builder image.
Build the binary locally, then use a minimal `Dockerfile`
that copies the pre-built executable into a `scratch` image —
a completely empty base image:

```bash
swift build -c release --swift-sdk aarch64-swift-linux-musl
```

```Dockerfile
FROM scratch
COPY .build/release/<executable-name> /

EXPOSE 8080
ENTRYPOINT ["/<executable-name>"]
```

The final image contains a single file: your executable.

If your service makes outbound TLS connections,
the image also needs CA certificates.
Copy them from any Linux image at build time:

```Dockerfile
FROM ubuntu:noble AS certs
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates

FROM scratch
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY .build/release/<executable-name> /

EXPOSE 8080
ENTRYPOINT ["/<executable-name>"]
```

Build the container image:

```bash
container build -t <my-app>:latest .
```

> Note: A `scratch`-based image doesn't include a shell,
> so you can't use `container run --rm -it <my-app> /bin/sh` to debug.
> If you need a shell for troubleshooting,
> use a slim base image during development and switch to `scratch` for production.

### Build and publish with Swift Container Plugin

The [Swift Container Plugin](https://github.com/apple/swift-container-plugin)
combines building, packaging, and pushing to a registry into a single command.
It builds your service with the Static Linux SDK,
packages the executable into a container image,
and publishes the image to a container registry — all without a Dockerfile.

Add the plugin to your `Package.swift`:

```swift
dependencies: [
.package(url: "https://github.com/apple/swift-container-plugin", from: "0.1.0"),
],
```

Then build and publish:

```bash
swift package --swift-sdk aarch64-swift-linux-musl \
build-container-image --repository registry.example.com/my-app
```

The plugin produces a minimal image equivalent to one from a `scratch`-based Dockerfile
and pushes it to the specified registry.
Run the published image with any container runtime:

```bash
container run -p 8080:8080 registry.example.com/my-app
```

> Tip: The container plugin is especially useful in CI pipelines
> where you want a single, repeatable command
> that produces a ready-to-deploy image.

### Deploy directly to a Linux machine

A static binary runs on any Linux machine, so you can copy it directly to a virtual machine or bare-metal server:

```bash
scp .build/release/<executable-name> user@server:/usr/local/bin/
```

On the server, run the executable directly:

```bash
ssh user@server /usr/local/bin/<executable-name>
```

Use your preferred configuration management tool, such as Ansible, Chef, Puppet, or shell scripts,
to automate deployment across multiple hosts.
Loading