9 cfg = config.services.gns3-server;
11 settingsFormat = pkgs.formats.ini { };
12 configFile = settingsFormat.generate "gns3-server.conf" cfg.settings;
17 doc = ./gns3-server.md;
18 maintainers = [ lib.maintainers.anthonyroussel ];
22 services.gns3-server = {
23 enable = lib.mkEnableOption "GNS3 Server daemon";
25 package = lib.mkPackageOption pkgs "gns3-server" { };
28 enable = lib.mkEnableOption "password based HTTP authentication to access the GNS3 Server";
31 type = lib.types.nullOr lib.types.str;
34 description = ''Username used to access the GNS3 Server.'';
37 passwordFile = lib.mkOption {
38 type = lib.types.nullOr lib.types.path;
40 example = "/run/secrets/gns3-server-password";
42 A file containing the password to access the GNS3 Server.
45 This should be a string, not a nix path, since nix paths
46 are copied into the world-readable nix store.
52 settings = lib.mkOption {
53 type = lib.types.submodule { freeformType = settingsFormat.type; };
60 The global options in `config` file in ini format.
62 Refer to <https://docs.gns3.com/docs/using-gns3/administration/gns3-server-configuration-file/>
63 for all available options.
69 type = lib.types.nullOr lib.types.path;
70 default = "/var/log/gns3/server.log";
71 description = ''Path of the file GNS3 Server should log to.'';
74 debug = lib.mkEnableOption "debug logging";
78 enable = lib.mkEnableOption "SSL encryption";
80 certFile = lib.mkOption {
81 type = lib.types.nullOr lib.types.path;
83 example = "/var/lib/gns3/ssl/server.pem";
85 Path to the SSL certificate file. This certificate will
86 be offered to, and may be verified by, clients.
90 keyFile = lib.mkOption {
91 type = lib.types.nullOr lib.types.path;
93 example = "/var/lib/gns3/ssl/server.key";
94 description = "Private key file for the certificate.";
99 enable = lib.mkEnableOption ''Dynamips support'';
100 package = lib.mkPackageOption pkgs "dynamips" { };
104 enable = lib.mkEnableOption ''uBridge support'';
105 package = lib.mkPackageOption pkgs "ubridge" { };
109 enable = lib.mkEnableOption ''VPCS support'';
110 package = lib.mkPackageOption pkgs "vpcs" { };
118 enableDocker = config.virtualisation.docker.enable;
119 enableLibvirtd = config.virtualisation.libvirtd.enable;
123 lib.mkIf cfg.enable {
126 assertion = cfg.ssl.enable -> cfg.ssl.certFile != null;
127 message = "Please provide a certificate to use for SSL encryption.";
130 assertion = cfg.ssl.enable -> cfg.ssl.keyFile != null;
131 message = "Please provide a private key to use for SSL encryption.";
134 assertion = cfg.auth.enable -> cfg.auth.user != null;
135 message = "Please provide a username to use for HTTP authentication.";
138 assertion = cfg.auth.enable -> cfg.auth.passwordFile != null;
139 message = "Please provide a password file to use for HTTP authentication.";
143 users.groups.gns3 = { };
145 users.groups.ubridge = lib.mkIf cfg.ubridge.enable { };
152 security.wrappers.ubridge = lib.mkIf cfg.ubridge.enable {
153 capabilities = "cap_net_raw,cap_net_admin=eip";
156 permissions = "u=rwx,g=rx,o=r";
157 source = lib.getExe cfg.ubridge.package;
160 services.gns3-server.settings = lib.mkMerge [
163 appliances_path = lib.mkDefault "/var/lib/gns3/appliances";
164 configs_path = lib.mkDefault "/var/lib/gns3/configs";
165 images_path = lib.mkDefault "/var/lib/gns3/images";
166 projects_path = lib.mkDefault "/var/lib/gns3/projects";
167 symbols_path = lib.mkDefault "/var/lib/gns3/symbols";
170 (lib.mkIf (cfg.ubridge.enable) {
171 Server.ubridge_path = lib.mkDefault "/run/wrappers/bin/ubridge";
173 (lib.mkIf (cfg.auth.enable) {
175 auth = lib.mkDefault (lib.boolToString cfg.auth.enable);
176 user = lib.mkDefault cfg.auth.user;
177 password = lib.mkDefault "@AUTH_PASSWORD@";
180 (lib.mkIf (cfg.vpcs.enable) {
181 VPCS.vpcs_path = lib.mkDefault (lib.getExe cfg.vpcs.package);
183 (lib.mkIf (cfg.dynamips.enable) {
184 Dynamips.dynamips_path = lib.mkDefault (lib.getExe cfg.dynamips.package);
188 systemd.services.gns3-server =
190 commandArgs = lib.cli.toGNUCommandLineShell { } {
191 config = "/etc/gns3/gns3_server.conf";
192 pid = "/run/gns3/server.pid";
194 ssl = cfg.ssl.enable;
195 # These are implicitly not set if `null`
196 certfile = cfg.ssl.certFile;
197 certkey = cfg.ssl.keyFile;
201 description = "GNS3 Server";
205 "network-online.target"
207 wantedBy = [ "multi-user.target" ];
208 wants = [ "network-online.target" ];
210 # configFile cannot be stored in RuntimeDirectory, because GNS3
211 # uses the `--config` base path to stores supplementary configuration files at runtime.
214 install -m660 ${configFile} /etc/gns3/gns3_server.conf
216 ${lib.optionalString cfg.auth.enable ''
217 ${pkgs.replace-secret}/bin/replace-secret \
219 "''${CREDENTIALS_DIRECTORY}/AUTH_PASSWORD" \
220 /etc/gns3/gns3_server.conf
224 path = lib.optional flags.enableLibvirtd pkgs.qemu;
226 reloadTriggers = [ configFile ];
229 ConfigurationDirectory = "gns3";
230 ConfigurationDirectoryMode = "0750";
231 Environment = "HOME=%S/gns3";
232 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
233 ExecStart = "${lib.getExe cfg.package} ${commandArgs}";
236 LoadCredential = lib.mkIf cfg.auth.enable [ "AUTH_PASSWORD:${cfg.auth.passwordFile}" ];
237 LogsDirectory = "gns3";
238 LogsDirectoryMode = "0750";
239 PIDFile = "/run/gns3/server.pid";
240 Restart = "on-failure";
242 RuntimeDirectory = "gns3";
243 StateDirectory = "gns3";
244 StateDirectoryMode = "0750";
245 SupplementaryGroups =
246 lib.optional flags.enableDocker "docker"
247 ++ lib.optional flags.enableLibvirtd "libvirtd"
248 ++ lib.optional cfg.ubridge.enable "ubridge";
250 WorkingDirectory = "%S/gns3";
252 # Required for ubridge integration to work
254 # GNS3 needs to run SUID binaries (ubridge)
255 # but NoNewPrivileges breaks execution of SUID binaries
257 NoNewPrivileges = false;
258 RestrictSUIDSGID = false;
259 PrivateUsers = false;
264 # ubridge needs access to tun/tap devices
268 ++ lib.optionals flags.enableLibvirtd [
271 DevicePolicy = "closed";
272 LockPersonality = true;
273 MemoryDenyWriteExecute = true;
275 # Don't restrict ProcSubset because python3Packages.psutil requires read access to /proc/stat
276 # ProcSubset = "pid";
278 ProtectControlGroups = true;
280 ProtectHostname = true;
281 ProtectKernelLogs = true;
282 ProtectKernelModules = true;
283 ProtectKernelTunables = true;
284 ProtectProc = "invisible";
285 ProtectSystem = "strict";
286 RestrictAddressFamilies = [
293 RestrictNamespaces = true;
294 RestrictRealtime = true;