You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

546 lines
17KB

  1. # Edit this configuration file to define what should be installed on
  2. # your system. Help is available in the configuration.nix(5) man page
  3. # and in the NixOS manual (accessible by running ‘nixos-help’).
  4. { config, pkgs, ... }:
  5. let
  6. netifWan = "enp0s31f6";
  7. netifLan = "enp3s0";
  8. netifWifi = "wlp4s0";
  9. netifSit = "henet0";
  10. hydraWwwOutputs = "/var/www/hydra-outputs";
  11. in
  12. {
  13. imports =
  14. [
  15. ./hardware-configuration.nix
  16. ./homu/nixos-module.nix
  17. ./backup-module.nix
  18. (builtins.fetchTarball {
  19. url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/v2.2.1/nixos-mailserver-v2.2.1.tar.gz";
  20. sha256 = "03d49v8qnid9g9rha0wg2z6vic06mhp0b049s3whccn1axvs2zzx";
  21. })
  22. ];
  23. # Use the systemd-boot EFI boot loader.
  24. boot.loader.systemd-boot.enable = true;
  25. boot.loader.efi.canTouchEfiVariables = true;
  26. security.apparmor.enable = true;
  27. security.pam.yubico = {
  28. enable = true;
  29. id = "49094";
  30. control = "required";
  31. };
  32. networking = {
  33. hostName = "nixbld";
  34. firewall = {
  35. allowedTCPPorts = [ 80 443 631 ];
  36. allowedUDPPorts = [ 53 67 631 ];
  37. };
  38. networkmanager.unmanaged = [ "interface-name:${netifLan}" "interface-name:${netifWifi}" ];
  39. interfaces."${netifLan}".ipv4.addresses = [{
  40. address = "192.168.1.1";
  41. prefixLength = 24;
  42. }];
  43. interfaces."${netifWifi}".ipv4.addresses = [{
  44. address = "192.168.12.1";
  45. prefixLength = 24;
  46. }];
  47. nat = {
  48. enable = true;
  49. externalInterface = netifWan;
  50. internalInterfaces = [ netifLan netifWifi ];
  51. };
  52. sits."${netifSit}" = {
  53. dev = netifWan;
  54. remote = "216.218.221.6";
  55. local = "42.200.147.171";
  56. ttl = 255;
  57. };
  58. interfaces."${netifSit}".ipv6 = {
  59. addresses = [{ address = "2001:470:18:629::2"; prefixLength = 64; }];
  60. routes = [{ address = "::"; prefixLength = 0; }];
  61. };
  62. };
  63. services.hostapd = {
  64. enable = true;
  65. interface = netifWifi;
  66. hwMode = "g";
  67. ssid = "M-Labs";
  68. wpaPassphrase = (import /etc/nixos/secret/wifi_password.nix);
  69. };
  70. services.dnsmasq = {
  71. enable = true;
  72. extraConfig = ''
  73. interface=${netifLan}
  74. interface=${netifWifi}
  75. bind-interfaces
  76. dhcp-range=interface:${netifLan},192.168.1.10,192.168.1.254,24h
  77. dhcp-range=interface:${netifWifi},192.168.12.10,192.168.12.254,24h
  78. '';
  79. };
  80. # Select internationalisation properties.
  81. i18n = {
  82. consoleFont = "Lat2-Terminus16";
  83. consoleKeyMap = "de";
  84. defaultLocale = "en_US.UTF-8";
  85. };
  86. # Set your time zone.
  87. time.timeZone = "Asia/Hong_Kong";
  88. # List packages installed in system profile. To search, run:
  89. # $ nix search wget
  90. environment.systemPackages = with pkgs; [
  91. wget vim git file lm_sensors acpi pciutils psmisc xc3sprog openocd telnet whois zip unzip
  92. irssi tmux adoptopenjdk-openj9-bin-11 tigervnc xorg.xauth icewm xterm xorg.xsetroot usbutils virtmanager imagemagick jq
  93. ];
  94. # Some programs need SUID wrappers, can be configured further or are
  95. # started in user sessions.
  96. # programs.mtr.enable = true;
  97. # programs.gnupg.agent = { enable = true; enableSSHSupport = true; };
  98. # List services that you want to enable:
  99. services.apcupsd.enable = true;
  100. services.apcupsd.configText = ''
  101. UPSTYPE usb
  102. NISIP 127.0.0.1
  103. BATTERYLEVEL 10
  104. MINUTES 5
  105. '';
  106. # Enable the OpenSSH daemon.
  107. services.openssh.enable = true;
  108. services.openssh.forwardX11 = true;
  109. programs.mosh.enable = true;
  110. programs.fish.enable = true;
  111. # Enable CUPS to print documents.
  112. services.avahi.enable = true;
  113. services.avahi.interfaces = [ netifLan ];
  114. services.avahi.publish.enable = true;
  115. services.avahi.publish.userServices = true;
  116. nixpkgs.config.allowUnfree = true;
  117. services.printing.enable = true;
  118. services.printing.drivers = [ pkgs.hplipWithPlugin ];
  119. services.printing.browsing = true;
  120. services.printing.listenAddresses = [ "192.168.1.1:631" ];
  121. services.printing.defaultShared = true;
  122. hardware.sane.enable = true;
  123. hardware.sane.extraBackends = [ pkgs.hplipWithPlugin ];
  124. users.extraGroups.plugdev = { };
  125. users.extraUsers.sb = {
  126. isNormalUser = true;
  127. extraGroups = ["wheel" "plugdev" "dialout" "lp" "scanner"];
  128. shell = pkgs.fish;
  129. };
  130. users.extraUsers.rj = {
  131. isNormalUser = true;
  132. extraGroups = ["wheel" "plugdev" "dialout"];
  133. };
  134. users.extraUsers.astro = {
  135. isNormalUser = true;
  136. extraGroups = ["plugdev" "dialout"];
  137. };
  138. users.extraUsers.whitequark = {
  139. isNormalUser = true;
  140. extraGroups = ["plugdev" "dialout"];
  141. };
  142. users.extraUsers.nix = {
  143. isNormalUser = true;
  144. };
  145. security.sudo.wheelNeedsPassword = false;
  146. security.hideProcessInformation = true;
  147. boot.kernel.sysctl."kernel.dmesg_restrict" = true;
  148. services.udev.packages = [ pkgs.openocd pkgs.sane-backends ];
  149. services.udev.extraRules = ''
  150. ACTION=="add", SUBSYSTEM=="tty", \
  151. ENV{ID_SERIAL}=="FTDI_Quad_RS232-HS", \
  152. ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:5:1.1", \
  153. SYMLINK+="ttyUSB_sayma-1_0"
  154. ACTION=="add", SUBSYSTEM=="tty", \
  155. ENV{ID_SERIAL}=="FTDI_Quad_RS232-HS", \
  156. ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:5:1.2", \
  157. SYMLINK+="ttyUSB_sayma-1_1"
  158. ACTION=="add", SUBSYSTEM=="tty", \
  159. ENV{ID_SERIAL}=="FTDI_Quad_RS232-HS", \
  160. ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:1:1.2", \
  161. SYMLINK+="ttyUSB_kasli-n1"
  162. '';
  163. nix.distributedBuilds = true;
  164. nix.buildMachines = [
  165. {
  166. hostName = "localhost";
  167. maxJobs = 4;
  168. system = "x86_64-linux";
  169. supportedFeatures = ["big-parallel"];
  170. }
  171. {
  172. hostName = "rpi-1";
  173. sshUser = "nix";
  174. sshKey = "/etc/nixos/secret/nix_id_rsa";
  175. maxJobs = 1;
  176. system = "aarch64-linux";
  177. }
  178. ];
  179. services.hydra = {
  180. enable = true;
  181. useSubstitutes = true;
  182. hydraURL = "https://nixbld.m-labs.hk";
  183. notificationSender = "hydra@m-labs.hk";
  184. minimumDiskFree = 15; # in GB
  185. minimumDiskFreeEvaluator = 1;
  186. extraConfig =
  187. ''
  188. binary_cache_secret_key_file = /etc/nixos/secret/nixbld.m-labs.hk-1
  189. max_output_size = 10000000000
  190. <runcommand>
  191. job = web:web:web
  192. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/web
  193. </runcommand>
  194. <runcommand>
  195. job = artiq:full:artiq-manual-html
  196. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-html-beta
  197. </runcommand>
  198. <runcommand>
  199. job = artiq:full:artiq-manual-latexpdf
  200. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-latexpdf-beta
  201. </runcommand>
  202. <runcommand>
  203. job = artiq:full:conda-channel
  204. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-conda-channel-beta
  205. </runcommand>
  206. '';
  207. };
  208. systemd.services.hydra-www-outputs-init = {
  209. description = "Set up a hydra-owned directory for build outputs";
  210. wantedBy = [ "multi-user.target" ];
  211. requiredBy = [ "hydra-queue-runner.service" ];
  212. before = [ "hydra-queue-runner.service" ];
  213. serviceConfig = {
  214. Type = "oneshot";
  215. ExecStart = [ "${pkgs.coreutils}/bin/mkdir -p ${hydraWwwOutputs}" "${pkgs.coreutils}/bin/chown hydra-queue-runner:hydra ${hydraWwwOutputs}" ];
  216. };
  217. };
  218. nix.extraOptions = ''
  219. secret-key-files = /etc/nixos/secret/nixbld.m-labs.hk-1
  220. '';
  221. nix.sandboxPaths = ["/opt"];
  222. virtualisation.libvirtd.enable = true;
  223. services.munin-node.enable = true;
  224. services.munin-cron = {
  225. enable = true;
  226. hosts = ''
  227. [${config.networking.hostName}]
  228. address localhost
  229. '';
  230. };
  231. services.mlabs-backup.enable = true;
  232. services.gitea = {
  233. enable = true;
  234. httpPort = 3001;
  235. rootUrl = "https://git.m-labs.hk/";
  236. appName = "M-Labs Git";
  237. cookieSecure = true;
  238. disableRegistration = true;
  239. extraConfig =
  240. ''
  241. [attachment]
  242. ALLOWED_TYPES = */*
  243. '';
  244. };
  245. services.mattermost = {
  246. enable = true;
  247. siteUrl = "https://chat.m-labs.hk/";
  248. mutableConfig = true;
  249. };
  250. services.matterbridge = {
  251. enable = true;
  252. configPath = "/etc/nixos/secret/matterbridge.toml";
  253. };
  254. nixpkgs.config.packageOverrides = super: let self = super.pkgs; in {
  255. hydra = super.hydra.overrideAttrs(oa: {
  256. patches = oa.patches or [] ++ [ ./hydra-conda.patch ./hydra-retry.patch ];
  257. hydraPath = oa.hydraPath + ":" + super.lib.makeBinPath [ super.jq ];
  258. });
  259. matterbridge = super.matterbridge.overrideAttrs(oa: {
  260. patches = oa.patches or [] ++ [ ./matterbridge-disable-github.patch ];
  261. });
  262. };
  263. security.acme.certs = {
  264. "nixbld.m-labs.hk" = {
  265. webroot = "/var/lib/acme/acme-challenge";
  266. extraDomains = {
  267. "m-labs.hk" = null;
  268. "www.m-labs.hk" = null;
  269. "conda.m-labs.hk" = null;
  270. "lab.m-labs.hk" = null;
  271. "git.m-labs.hk" = null;
  272. "chat.m-labs.hk" = null;
  273. "hooks.m-labs.hk" = null;
  274. "forum.m-labs.hk" = null;
  275. "fractalide.org" = null;
  276. "www.fractalide.org" = null;
  277. "hydra.fractalide.org" = null;
  278. "git.fractalide.org" = null;
  279. "puff.fractalide.org" = null;
  280. "luceo-mainnet-rest.fractalide.org" = null;
  281. "luceo-mainnet-grpc.fractalide.org" = null;
  282. "luceo-testnet-rest.fractalide.org" = null;
  283. "luceo-testnet-grpc.fractalide.org" = null;
  284. };
  285. };
  286. };
  287. services.nginx = {
  288. enable = true;
  289. recommendedProxySettings = true;
  290. recommendedGzipSettings = true;
  291. virtualHosts = let
  292. mainWebsite = {
  293. addSSL = true;
  294. useACMEHost = "nixbld.m-labs.hk";
  295. root = "${hydraWwwOutputs}/web";
  296. extraConfig = ''
  297. error_page 404 /404.html;
  298. '';
  299. locations."^~ /fonts/".extraConfig = ''
  300. expires 60d;
  301. '';
  302. locations."^~ /js/".extraConfig = ''
  303. expires 60d;
  304. '';
  305. locations."/MathJax/" = {
  306. alias = "/var/www/MathJax/";
  307. extraConfig = ''
  308. expires 60d;
  309. '';
  310. };
  311. # legacy URLs, redirect to avoid breaking people's bookmarks
  312. locations."/gateware.html".extraConfig = ''
  313. return 301 /gateware/migen/;
  314. '';
  315. locations."/migen".extraConfig = ''
  316. return 301 /gateware/migen/;
  317. '';
  318. locations."/artiq".extraConfig = ''
  319. return 301 /experiment-control/artiq/;
  320. '';
  321. locations."/artiq/resources.html".extraConfig = ''
  322. return 301 /experiment-control/resources/;
  323. '';
  324. # autogenerated ARTIQ manuals
  325. locations."/artiq/manual-beta/" = {
  326. alias = "${hydraWwwOutputs}/artiq-manual-html-beta/share/doc/artiq-manual/html/";
  327. };
  328. locations."=/artiq/manual-beta.pdf" = {
  329. alias = "${hydraWwwOutputs}/artiq-manual-latexpdf-beta/share/doc/artiq-manual/ARTIQ.pdf";
  330. };
  331. # legacy content
  332. locations."/migen/manual/" = {
  333. alias = "/var/www/m-labs.hk.old/migen/manual/";
  334. };
  335. locations."/artiq/manual/" = {
  336. alias = "/var/www/m-labs.hk.old/artiq/manual-release-4/";
  337. };
  338. locations."/artiq/manual-release-4/" = {
  339. alias = "/var/www/m-labs.hk.old/artiq/manual-release-4/";
  340. };
  341. locations."/artiq/manual-release-3/" = {
  342. alias = "/var/www/m-labs.hk.old/artiq/manual-release-3/";
  343. };
  344. };
  345. in {
  346. "m-labs.hk" = mainWebsite;
  347. "www.m-labs.hk" = mainWebsite;
  348. "lab.m-labs.hk" = {
  349. addSSL = true;
  350. useACMEHost = "nixbld.m-labs.hk";
  351. locations."/munin/".alias = "/var/www/munin/";
  352. locations."/munin".extraConfig = ''
  353. auth_basic "Munin";
  354. auth_basic_user_file /etc/nixos/secret/muninpasswd;
  355. '';
  356. locations."/homu/".proxyPass = "http://127.0.0.1:54856/";
  357. };
  358. "nixbld.m-labs.hk" = {
  359. forceSSL = true;
  360. useACMEHost = "nixbld.m-labs.hk";
  361. locations."/".proxyPass = "http://127.0.0.1:3000";
  362. };
  363. "conda.m-labs.hk" = {
  364. forceSSL = true;
  365. useACMEHost = "nixbld.m-labs.hk";
  366. locations."/artiq-beta/" = {
  367. alias = "${hydraWwwOutputs}/artiq-conda-channel-beta/";
  368. extraConfig = ''
  369. autoindex on;
  370. index bogus_index_file;
  371. '';
  372. };
  373. };
  374. "git.m-labs.hk" = {
  375. forceSSL = true;
  376. useACMEHost = "nixbld.m-labs.hk";
  377. locations."/".proxyPass = "http://127.0.0.1:3001";
  378. extraConfig = ''
  379. client_max_body_size 300M;
  380. '';
  381. };
  382. "chat.m-labs.hk" = {
  383. forceSSL = true;
  384. useACMEHost = "nixbld.m-labs.hk";
  385. locations."/".proxyPass = "http://127.0.0.1:8065";
  386. locations."~ /api/v[0-9]+/(users/)?websocket$".proxyPass = "http://127.0.0.1:8065";
  387. locations."~ /api/v[0-9]+/(users/)?websocket$".proxyWebsockets = true;
  388. };
  389. "hooks.m-labs.hk" = {
  390. forceSSL = true;
  391. useACMEHost = "nixbld.m-labs.hk";
  392. locations."/".extraConfig = ''
  393. include ${pkgs.nginx}/conf/uwsgi_params;
  394. uwsgi_pass unix:${config.services.uwsgi.runDir}/uwsgi.sock;
  395. '';
  396. };
  397. "forum.m-labs.hk" = {
  398. forceSSL = true;
  399. useACMEHost = "nixbld.m-labs.hk";
  400. root = "/var/www/flarum/public";
  401. locations."~ \.php$".extraConfig = ''
  402. fastcgi_pass unix:${config.services.phpfpm.pools.flarum.socket};
  403. fastcgi_index index.php;
  404. '';
  405. extraConfig = ''
  406. index index.php;
  407. include /var/www/flarum/.nginx.conf;
  408. '';
  409. };
  410. "hydra.fractalide.org" = {
  411. forceSSL = true;
  412. useACMEHost = "nixbld.m-labs.hk";
  413. locations."/".proxyPass = "http://192.168.1.204:3000";
  414. };
  415. "git.fractalide.org" = {
  416. forceSSL = true;
  417. useACMEHost = "nixbld.m-labs.hk";
  418. locations."/".proxyPass = "http://192.168.1.204:3001";
  419. };
  420. "fractalide.org" = {
  421. forceSSL = true;
  422. useACMEHost = "nixbld.m-labs.hk";
  423. locations."/".proxyPass = "http://192.168.1.204:3002";
  424. };
  425. "www.fractalide.org" = {
  426. forceSSL = true;
  427. useACMEHost = "nixbld.m-labs.hk";
  428. locations."/".proxyPass = "http://192.168.1.204:3002";
  429. };
  430. "puff.fractalide.org" = {
  431. forceSSL = true;
  432. useACMEHost = "nixbld.m-labs.hk";
  433. locations."/".proxyPass = "http://192.168.1.204:3008";
  434. };
  435. "luceo-mainnet-rest.fractalide.org" = {
  436. forceSSL = true;
  437. useACMEHost = "nixbld.m-labs.hk";
  438. locations."/".proxyPass = "http://192.168.1.204:3004";
  439. };
  440. "luceo-mainnet-grpc.fractalide.org" = {
  441. forceSSL = true;
  442. useACMEHost = "nixbld.m-labs.hk";
  443. locations."/".proxyPass = "http://192.168.1.204:3005";
  444. };
  445. "luceo-testnet-rest.fractalide.org" = {
  446. forceSSL = true;
  447. useACMEHost = "nixbld.m-labs.hk";
  448. locations."/".proxyPass = "http://192.168.1.204:3006";
  449. };
  450. "luceo-testnet-grpc.fractalide.org" = {
  451. forceSSL = true;
  452. useACMEHost = "nixbld.m-labs.hk";
  453. locations."/".proxyPass = "http://192.168.1.204:3007";
  454. };
  455. };
  456. };
  457. services.uwsgi = {
  458. enable = true;
  459. plugins = [ "python3" ];
  460. instance = {
  461. type = "emperor";
  462. vassals = {
  463. mattermostgithub = import ./mattermost-github-integration/uwsgi-config.nix { inherit config pkgs; };
  464. };
  465. };
  466. };
  467. services.mysql = {
  468. enable = true;
  469. package = pkgs.mariadb;
  470. };
  471. services.phpfpm.pools.flarum = {
  472. user = "nobody";
  473. settings = {
  474. "listen.owner" = "nginx";
  475. "listen.group" = "nginx";
  476. "listen.mode" = "0600";
  477. "pm" = "dynamic";
  478. "pm.max_children" = 5;
  479. "pm.start_servers" = 2;
  480. "pm.min_spare_servers" = 1;
  481. "pm.max_spare_servers" = 3;
  482. "pm.max_requests" = 500;
  483. };
  484. };
  485. services.homu = {
  486. enable = true;
  487. config = "/etc/nixos/secret/homu.toml";
  488. };
  489. mailserver = {
  490. enable = true;
  491. localDnsResolver = false; # conflicts with dnsmasq
  492. # Some mail servers do reverse DNS lookups to filter spam.
  493. # Getting a proper reverse DNS record from ISP is difficult, so use whatever already exists.
  494. fqdn = "42-200-147-171.static.imsbiz.com";
  495. domains = [ "nmigen.org" ];
  496. loginAccounts = (import /etc/nixos/secret/email_accounts.nix);
  497. certificateScheme = 3;
  498. };
  499. security.acme.certs."${config.mailserver.fqdn}".extraDomains = {
  500. "mail.nmigen.org" = null;
  501. };
  502. # This value determines the NixOS release with which your system is to be
  503. # compatible, in order to avoid breaking some software such as database
  504. # servers. You should change this only after NixOS release notes say you
  505. # should.
  506. system.stateVersion = "18.09"; # Did you read the comment?
  507. }