1# pkgs.portableService {#sec-pkgs-portableService}
2
3`pkgs.portableService` is a function to create [Portable Services](https://systemd.io/PORTABLE_SERVICES/) in a read-only, immutable, `squashfs` raw disk image.
4This lets you use Nix to build images which can be run on many recent Linux distributions.
5
6::: {.note}
7Portable services are supported starting with systemd 239 (released on 2018-06-22).
8:::
9
10The generated image will contain the file system structure as required by the Portable Services specification, along with the packages given to `portableService` and all of their dependencies.
11When generated, the image will exist in the Nix store with the `.raw` file extension, as required by the specification.
12See [](#ex-portableService-hello) to understand how to use the output of `portableService`.
13
14## Inputs {#ssec-pkgs-portableService-inputs}
15
16`portableService` expects one argument with the following attributes:
17
18`pname` (String)
19
20: The name of the portable service.
21 The generated image will be named according to the template `$pname_$version.raw`, which is supported by the Portable Services specification.
22
23`version` (String)
24
25: The version of the portable service.
26 The generated image will be named according to the template `$pname_$version.raw`, which is supported by the Portable Services specification.
27
28`units` (List of Attribute Set)
29
30: A list of derivations for systemd unit files.
31 Each derivation must produce a single file, and must have a name that starts with the value of `pname` and ends with the suffix of the unit type (e.g. ".service", ".socket", ".timer", and so on).
32 See [](#ex-portableService-hello) to better understand this naming constraint.
33
34`description` (String or Null; _optional_)
35
36: If specified, the value is added as `PORTABLE_PRETTY_NAME` to the `/etc/os-release` file in the generated image.
37 This could be used to provide more information to anyone inspecting the image.
38
39 _Default value:_ `null`.
40
41`homepage` (String or Null; _optional_)
42
43: If specified, the value is added as `HOME_URL` to the `/etc/os-release` file in the generated image.
44 This could be used to provide more information to anyone inspecting the image.
45
46 _Default value:_ `null`.
47
48`symlinks` (List of Attribute Set; _optional_)
49
50: A list of attribute sets in the format `{object, symlink}`.
51 For each item in the list, `portableService` will create a symlink in the path specified by `symlink` (relative to the root of the image) that points to `object`.
52
53 All packages that `object` depends on and their dependencies are automatically copied into the image.
54
55 This can be used to create symlinks for applications that assume some files to exist globally (`/etc/ssl` or `/bin/bash`, for example).
56 See [](#ex-portableService-symlinks) to understand how to do that.
57
58 _Default value:_ `[]`.
59
60`contents` (List of Attribute Set; _optional_)
61
62: A list of additional derivations to be included as-is in the image.
63 These derivations will be included directly in a `/nix/store` directory inside the image.
64
65 _Default value:_ `[]`.
66
67`squashfsTools` (Attribute Set; _optional_)
68
69: Allows you to override the package that provides {manpage}`mksquashfs(1)`, which is used internally by `portableService`.
70
71 _Default value:_ `pkgs.squashfsTools`.
72
73`squash-compression` (String; _optional_)
74
75: Passed as the compression option to {manpage}`mksquashfs(1)`, which is used internally by `portableService`.
76
77 _Default value:_ `"xz -Xdict-size 100%"`.
78
79`squash-block-size` (String; _optional_)
80
81: Passed as the block size option to {manpage}`mksquashfs(1)`, which is used internally by `portableService`.
82
83 _Default value:_ `"1M"`.
84
85## Examples {#ssec-pkgs-portableService-examples}
86
87[]{#ex-pkgs-portableService}
88:::{.example #ex-portableService-hello}
89# Building a Portable Service image
90
91The following example builds a Portable Service image with the `hello` package, along with a service unit that runs it.
92
93```nix
94{
95 lib,
96 writeText,
97 portableService,
98 hello,
99}:
100let
101 hello-service = writeText "hello.service" ''
102 [Unit]
103 Description=Hello world service
104
105 [Service]
106 Type=oneshot
107 ExecStart=${lib.getExe hello}
108 '';
109in
110portableService {
111 pname = "hello";
112 inherit (hello) version;
113 units = [ hello-service ];
114}
115```
116
117After building the package, the generated image can be loaded into a system through {manpage}`portablectl(1)`:
118
119```shell
120$ nix-build
121(some output removed for clarity)
122/nix/store/8c20z1vh7z8w8dwagl8w87b45dn5k6iq-hello-img-2.12.1
123
124$ portablectl attach /nix/store/8c20z1vh7z8w8dwagl8w87b45dn5k6iq-hello-img-2.12.1/hello_2.12.1.raw
125Created directory /etc/systemd/system.attached.
126Created directory /etc/systemd/system.attached/hello.service.d.
127Written /etc/systemd/system.attached/hello.service.d/20-portable.conf.
128Created symlink /etc/systemd/system.attached/hello.service.d/10-profile.conf → /usr/lib/systemd/portable/profile/default/service.conf.
129Copied /etc/systemd/system.attached/hello.service.
130Created symlink /etc/portables/hello_2.12.1.raw → /nix/store/8c20z1vh7z8w8dwagl8w87b45dn5k6iq-hello-img-2.12.1/hello_2.12.1.raw.
131
132$ systemctl start hello
133$ journalctl -u hello
134Feb 28 22:39:16 hostname systemd[1]: Starting Hello world service...
135Feb 28 22:39:16 hostname hello[102887]: Hello, world!
136Feb 28 22:39:16 hostname systemd[1]: hello.service: Deactivated successfully.
137Feb 28 22:39:16 hostname systemd[1]: Finished Hello world service.
138
139$ portablectl detach hello_2.12.1
140Removed /etc/systemd/system.attached/hello.service.
141Removed /etc/systemd/system.attached/hello.service.d/10-profile.conf.
142Removed /etc/systemd/system.attached/hello.service.d/20-portable.conf.
143Removed /etc/systemd/system.attached/hello.service.d.
144Removed /etc/portables/hello_2.12.1.raw.
145Removed /etc/systemd/system.attached.
146```
147:::
148
149:::{.example #ex-portableService-symlinks}
150# Specifying symlinks when building a Portable Service image
151
152Some services may expect files or directories to be available globally.
153An example is a service which expects all trusted SSL certificates to exist in a specific location by default.
154
155To make things available globally, you must specify the `symlinks` attribute when using `portableService`.
156The following package builds on the package from [](#ex-portableService-hello) to make `/etc/ssl` available globally (this is only for illustrative purposes, because `hello` doesn't use `/etc/ssl`).
157
158```nix
159{
160 lib,
161 writeText,
162 portableService,
163 hello,
164 cacert,
165}:
166let
167 hello-service = writeText "hello.service" ''
168 [Unit]
169 Description=Hello world service
170
171 [Service]
172 Type=oneshot
173 ExecStart=${lib.getExe hello}
174 '';
175in
176portableService {
177 pname = "hello";
178 inherit (hello) version;
179 units = [ hello-service ];
180 symlinks = [
181 {
182 object = "${cacert}/etc/ssl";
183 symlink = "/etc/ssl";
184 }
185 ];
186}
187```
188:::