1 { pkgs, config, lib, ... }:
4 cfg = config.services.cockpit;
5 inherit (lib) types mkEnableOption mkOption mkIf literalMD mkPackageOption;
6 settingsFormat = pkgs.formats.ini {};
10 enable = mkEnableOption "Cockpit";
12 package = mkPackageOption pkgs "Cockpit" {
13 default = [ "cockpit" ];
16 settings = lib.mkOption {
17 type = settingsFormat.type;
22 Settings for cockpit that will be saved in /etc/cockpit/cockpit.conf.
24 See the [documentation](https://cockpit-project.org/guide/latest/cockpit.conf.5.html), that is also available with `man cockpit.conf.5` for details.
29 description = "Port where cockpit will listen.";
34 openFirewall = mkOption {
35 description = "Open port for cockpit.";
41 config = mkIf cfg.enable {
43 # expose cockpit-bridge system-wide
44 environment.systemPackages = [ cfg.package ];
46 # allow cockpit to find its plugins
47 environment.pathsToLink = [ "/share/cockpit" ];
49 # generate cockpit settings
50 environment.etc."cockpit/cockpit.conf".source = settingsFormat.generate "cockpit.conf" cfg.settings;
52 security.pam.services.cockpit = {};
54 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
56 # units are in reverse sort order if you ls $out/lib/systemd/system
57 # all these units are basically verbatim translated from upstream
59 # Translation from $out/lib/systemd/system/systemd-cockpithttps.slice
60 systemd.slices.system-cockpithttps = {
61 description = "Resource limits for all cockpit-ws-https@.service instances";
69 # Translation from $out/lib/systemd/system/cockpit-wsinstance-https@.socket
70 systemd.sockets."cockpit-wsinstance-https@" = {
72 Description = "Socket for Cockpit Web Service https instance %I";
73 BindsTo = [ "cockpit.service" "cockpit-wsinstance-https@%i.service" ];
74 # clean up the socket after the service exits, to prevent fd leak
75 # this also effectively prevents a DoS by starting arbitrarily many sockets, as
76 # the services are resource-limited by system-cockpithttps.slice
77 Documentation = "man:cockpit-ws(8)";
80 ListenStream = "/run/cockpit/wsinstance/https@%i.sock";
86 # Translation from $out/lib/systemd/system/cockpit-wsinstance-https@.service
87 systemd.services."cockpit-wsinstance-https@" = {
88 description = "Cockpit Web Service https instance %I";
89 bindsTo = [ "cockpit.service"];
90 path = [ cfg.package ];
91 documentation = [ "man:cockpit-ws(8)" ];
93 Slice = "system-cockpithttps.slice";
94 ExecStart = "${cfg.package}/libexec/cockpit-ws --for-tls-proxy --port=0";
100 # Translation from $out/lib/systemd/system/cockpit-wsinstance-http.socket
101 systemd.sockets.cockpit-wsinstance-http = {
103 Description = "Socket for Cockpit Web Service http instance";
104 BindsTo = "cockpit.service";
105 Documentation = "man:cockpit-ws(8)";
108 ListenStream = "/run/cockpit/wsinstance/http.sock";
114 # Translation from $out/lib/systemd/system/cockpit-wsinstance-https-factory.socket
115 systemd.sockets.cockpit-wsinstance-https-factory = {
117 Description = "Socket for Cockpit Web Service https instance factory";
118 BindsTo = "cockpit.service";
119 Documentation = "man:cockpit-ws(8)";
122 ListenStream = "/run/cockpit/wsinstance/https-factory.sock";
129 # Translation from $out/lib/systemd/system/cockpit-wsinstance-https-factory@.service
130 systemd.services."cockpit-wsinstance-https-factory@" = {
131 description = "Cockpit Web Service https instance factory";
132 documentation = [ "man:cockpit-ws(8)" ];
133 path = [ cfg.package ];
135 ExecStart = "${cfg.package}/libexec/cockpit-wsinstance-factory";
140 # Translation from $out/lib/systemd/system/cockpit-wsinstance-http.service
141 systemd.services."cockpit-wsinstance-http" = {
142 description = "Cockpit Web Service http instance";
143 bindsTo = [ "cockpit.service" ];
144 path = [ cfg.package ];
145 documentation = [ "man:cockpit-ws(8)" ];
147 ExecStart = "${cfg.package}/libexec/cockpit-ws --no-tls --port=0";
153 # Translation from $out/lib/systemd/system/cockpit.socket
154 systemd.sockets."cockpit" = {
156 Description = "Cockpit Web Service Socket";
157 Documentation = "man:cockpit-ws(8)";
158 Wants = "cockpit-motd.service";
161 ListenStream = cfg.port;
163 "-${cfg.package}/share/cockpit/motd/update-motd \"\" localhost"
164 "-${pkgs.coreutils}/bin/ln -snf active.motd /run/cockpit/motd"
166 ExecStopPost = "-${pkgs.coreutils}/bin/ln -snf inactive.motd /run/cockpit/motd";
168 wantedBy = [ "sockets.target" ];
171 # Translation from $out/lib/systemd/system/cockpit.service
172 systemd.services."cockpit" = {
173 description = "Cockpit Web Service";
174 documentation = [ "man:cockpit-ws(8)" ];
175 restartIfChanged = true;
176 path = with pkgs; [ coreutils cfg.package ];
177 requires = [ "cockpit.socket" "cockpit-wsinstance-http.socket" "cockpit-wsinstance-https-factory.socket" ];
178 after = [ "cockpit-wsinstance-http.socket" "cockpit-wsinstance-https-factory.socket" ];
180 G_MESSAGES_DEBUG = "cockpit-ws,cockpit-bridge";
183 RuntimeDirectory="cockpit/tls";
185 # cockpit-tls runs in a more constrained environment, these + means that these commands
186 # will run with full privilege instead of inside that constrained environment
187 # See https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart= for details
188 "+${cfg.package}/libexec/cockpit-certificate-ensure --for-cockpit-tls"
190 ExecStart = "${cfg.package}/libexec/cockpit-tls";
193 NoNewPrivileges = true;
194 ProtectSystem = "strict";
197 PrivateDevices = true;
198 ProtectKernelTunables = true;
199 RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
200 MemoryDenyWriteExecute = true;
204 # Translation from $out/lib/systemd/system/cockpit-motd.service
205 # This part basically implements a motd state machine:
206 # - If cockpit.socket is enabled then /run/cockpit/motd points to /run/cockpit/active.motd
207 # - If cockpit.socket is disabled then /run/cockpit/motd points to /run/cockpit/inactive.motd
208 # - As cockpit.socket is disabled by default, /run/cockpit/motd points to /run/cockpit/inactive.motd
209 # /run/cockpit/active.motd is generated dynamically by cockpit-motd.service
210 systemd.services."cockpit-motd" = {
211 path = with pkgs; [ nettools ];
214 ExecStart = "${cfg.package}/share/cockpit/motd/update-motd";
216 description = "Cockpit motd updater service";
217 documentation = [ "man:cockpit-ws(8)" ];
218 wants = [ "network.target" ];
219 after = [ "network.target" "cockpit.socket" ];
222 systemd.tmpfiles.rules = [ # From $out/lib/tmpfiles.d/cockpit-tmpfiles.conf
223 "C /run/cockpit/inactive.motd 0640 root root - ${cfg.package}/share/cockpit/motd/inactive.motd"
224 "f /run/cockpit/active.motd 0640 root root -"
225 "L+ /run/cockpit/motd - - - - inactive.motd"
226 "d /etc/cockpit/ws-certs.d 0600 root root 0"
230 meta.maintainers = pkgs.cockpit.meta.maintainers;