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.

781 lines
27 KiB

  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 = "enp4s0";
  7. netifLan = "enp5s0f1";
  8. netifWifi = "wlp6s0";
  9. netifSit = "henet0";
  10. hydraWwwOutputs = "/var/www/hydra-outputs";
  11. in
  12. {
  13. imports =
  14. [
  15. ./hardware-configuration.nix
  16. ./backup-module.nix
  17. ./github-backup-module.nix
  18. ./rt.nix
  19. ];
  20. boot.loader.grub.enable = true;
  21. boot.loader.grub.copyKernels = true;
  22. boot.loader.grub.device = "nodev";
  23. boot.loader.grub.efiSupport = true;
  24. boot.loader.efi.canTouchEfiVariables = true;
  25. boot.supportedFilesystems = ["zfs"];
  26. boot.kernelParams = ["zfs.l2arc_write_max=536870912"];
  27. services.zfs.autoScrub.enable = true;
  28. services.zfs.autoScrub.interval = "monthly";
  29. services.zfs.autoSnapshot.enable = true;
  30. systemd.suppressedSystemUnits = [
  31. "hibernate.target"
  32. "suspend.target"
  33. "suspend-then-hibernate.target"
  34. "sleep.target"
  35. "hybrid-sleep.target"
  36. "systemd-hibernate.service"
  37. "systemd-hybrid-sleep.service"
  38. "systemd-suspend.service"
  39. "systemd-suspend-then-hibernate.service"
  40. ];
  41. security.apparmor.enable = true;
  42. networking = {
  43. hostName = "nixbld";
  44. hostId = "e423f012";
  45. firewall = {
  46. allowedTCPPorts = [ 80 443 ];
  47. allowedUDPPorts = [ 53 67 ];
  48. trustedInterfaces = [ netifLan ];
  49. };
  50. interfaces."${netifWan}".useDHCP = true;
  51. interfaces."${netifLan}" = {
  52. ipv4.addresses = [{
  53. address = "192.168.1.1";
  54. prefixLength = 24;
  55. }];
  56. ipv6.addresses = [{
  57. address = "2001:470:f821:1::";
  58. prefixLength = 64;
  59. }];
  60. ipv4.routes = [{
  61. address = "192.168.13.0";
  62. prefixLength = 24;
  63. via = "192.168.1.30";
  64. }];
  65. ipv6.routes = [{
  66. address = "2001:470:f821:3::";
  67. prefixLength = 64;
  68. via = "2001:470:f821:1:dea6:32ff:fe95:2fcf";
  69. }];
  70. };
  71. interfaces."${netifWifi}" = {
  72. ipv4.addresses = [{
  73. address = "192.168.12.1";
  74. prefixLength = 24;
  75. }];
  76. ipv6.addresses = [{
  77. address = "2001:470:f821:2::";
  78. prefixLength = 64;
  79. }];
  80. };
  81. nat = {
  82. enable = true;
  83. externalInterface = netifWan;
  84. internalInterfaces = [ netifLan netifWifi ];
  85. forwardPorts = [
  86. { sourcePort = 2201; destination = "192.168.1.201:22"; proto = "tcp"; }
  87. { sourcePort = 2202; destination = "192.168.1.202:22"; proto = "tcp"; }
  88. { sourcePort = 2203; destination = "192.168.1.203:22"; proto = "tcp"; }
  89. { sourcePort = 2204; destination = "192.168.1.204:22"; proto = "tcp"; }
  90. ];
  91. extraCommands = ''
  92. iptables -w -N block-lan-from-wifi
  93. iptables -w -A block-lan-from-wifi -i ${netifLan} -o ${netifWifi} -j DROP
  94. iptables -w -A block-lan-from-wifi -i ${netifWifi} -o ${netifLan} -j DROP
  95. iptables -w -A FORWARD -j block-lan-from-wifi
  96. '';
  97. extraStopCommands = ''
  98. iptables -w -D FORWARD -j block-lan-from-wifi 2>/dev/null|| true
  99. iptables -w -F block-lan-from-wifi 2>/dev/null|| true
  100. iptables -w -X block-lan-from-wifi 2>/dev/null|| true
  101. '';
  102. };
  103. sits."${netifSit}" = {
  104. dev = netifWan;
  105. remote = "216.218.221.6";
  106. local = "42.200.147.171";
  107. ttl = 255;
  108. };
  109. interfaces."${netifSit}".ipv6 = {
  110. addresses = [{ address = "2001:470:18:629::2"; prefixLength = 64; }];
  111. routes = [{ address = "::"; prefixLength = 0; }];
  112. };
  113. };
  114. boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = "1";
  115. boot.kernel.sysctl."net.ipv6.conf.default.forwarding" = "1";
  116. boot.kernel.sysctl."net.ipv6.conf.${netifLan}.accept_dad" = "0";
  117. boot.kernel.sysctl."net.ipv6.conf.${netifWifi}.accept_dad" = "0";
  118. services.unbound = {
  119. enable = true;
  120. settings = {
  121. server = {
  122. port = 5353;
  123. };
  124. };
  125. };
  126. services.hostapd = {
  127. enable = true;
  128. interface = netifWifi;
  129. hwMode = "g";
  130. ssid = "M-Labs";
  131. wpaPassphrase = (import /etc/nixos/secret/wifi_password.nix);
  132. extraConfig = ''
  133. ieee80211d=1
  134. country_code=HK
  135. ieee80211n=1
  136. wmm_enabled=1
  137. auth_algs=1
  138. wpa_key_mgmt=WPA-PSK
  139. rsn_pairwise=CCMP
  140. '';
  141. };
  142. services.dnsmasq = {
  143. enable = true;
  144. servers = ["::1#5353"];
  145. extraConfig = ''
  146. interface=${netifLan}
  147. interface=${netifWifi}
  148. bind-interfaces
  149. dhcp-range=interface:${netifLan},192.168.1.81,192.168.1.254,24h
  150. dhcp-range=interface:${netifWifi},192.168.12.10,192.168.12.254,24h
  151. enable-ra
  152. dhcp-range=interface:${netifLan},::,constructor:${netifLan},ra-names
  153. dhcp-range=interface:${netifWifi},::,constructor:${netifWifi},ra-only
  154. no-resolv
  155. # Static IPv4s to make Red Pitayas with factory firmware less annoying
  156. dhcp-host=rp-f05cc9,192.168.1.190
  157. dhcp-host=rp-f0612e,192.168.1.191
  158. # Static IPv4s to make port redirections work
  159. dhcp-host=rpi-1,192.168.1.201
  160. dhcp-host=rpi-2,192.168.1.202
  161. dhcp-host=rpi-3,192.168.1.203
  162. dhcp-host=rpi-4,192.168.1.204
  163. # Static IP addresses for non-DHCP boards
  164. address=/rpi-ext/192.168.1.30
  165. address=/rpi-ext/2001:470:f821:1:dea6:32ff:fe95:2fcf
  166. address=/thermostat/192.168.1.26
  167. address=/powercycler/192.168.1.31
  168. address=/kc705/192.168.1.50
  169. address=/zynq-experiments/192.168.1.51
  170. address=/zc706/192.168.1.52
  171. address=/zc706-2/192.168.1.53
  172. address=/cora-z7/192.168.1.54
  173. address=/rust-pitaya/192.168.1.55
  174. address=/sayma/192.168.1.60
  175. address=/metlino/192.168.1.65
  176. address=/kasli/192.168.1.70
  177. address=/kasli-customer/192.168.1.75
  178. address=/stabilizer-customer/192.168.1.76
  179. # uTCA MCH from NAT
  180. address=/tschernobyl/192.168.1.80
  181. '';
  182. };
  183. # Select internationalisation properties.
  184. i18n.defaultLocale = "en_US.UTF-8";
  185. console = {
  186. font = "Lat2-Terminus16";
  187. keyMap = "de";
  188. };
  189. # Set your time zone.
  190. time.timeZone = "Asia/Hong_Kong";
  191. # List packages installed in system profile. To search, run:
  192. # $ nix search wget
  193. environment.systemPackages = with pkgs; [
  194. wget vim git file lm_sensors acpi pciutils psmisc telnet nixopsUnstable
  195. irssi tmux usbutils imagemagick jq zip unzip
  196. iw
  197. nvme-cli
  198. borgbackup
  199. ];
  200. # Some programs need SUID wrappers, can be configured further or are
  201. # started in user sessions.
  202. # programs.mtr.enable = true;
  203. # programs.gnupg.agent = { enable = true; enableSSHSupport = true; };
  204. # List services that you want to enable:
  205. services.apcupsd.enable = true;
  206. services.apcupsd.configText = ''
  207. UPSTYPE usb
  208. NISIP 127.0.0.1
  209. BATTERYLEVEL 10
  210. MINUTES 5
  211. '';
  212. # Enable the OpenSSH daemon.
  213. services.openssh.enable = true;
  214. services.openssh.forwardX11 = true;
  215. services.openssh.passwordAuthentication = false;
  216. programs.mosh.enable = true;
  217. programs.fish.enable = true;
  218. # Enable CUPS to print documents.
  219. services.avahi.enable = true;
  220. services.avahi.interfaces = [ netifLan ];
  221. services.avahi.publish.enable = true;
  222. services.avahi.publish.userServices = true;
  223. nixpkgs.config.allowUnfree = true;
  224. services.printing.enable = true;
  225. services.printing.drivers = [ pkgs.hplipWithPlugin ];
  226. services.printing.browsing = true;
  227. services.printing.listenAddresses = [ "*:631" ];
  228. services.printing.defaultShared = true;
  229. hardware.sane.enable = true;
  230. hardware.sane.extraBackends = [ pkgs.hplipWithPlugin ];
  231. users.extraUsers.sb = {
  232. isNormalUser = true;
  233. extraGroups = ["wheel" "lp" "scanner"];
  234. openssh.authorizedKeys.keys = [
  235. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyPk5WyFoWSvF4ozehxcVBoZ+UHgrI7VW/OoQfFFwIQe0qvetUZBMZwR2FwkLPAMZV8zz1v4EfncudEkVghy4P+/YVLlDjqDq9zwZnh8Nd/ifu84wmcNWHT2UcqnhjniCdshL8a44memzABnxfLLv+sXhP2x32cJAamo5y6fukr2qLp2jbXzR+3sv3klE0ruUXis/BR1lLqNJEYP8jB6fLn2sLKinnZPfn6DwVOk10mGeQsdME/eGl3phpjhODH9JW5V2V5nJBbC0rBnq+78dyArKVqjPSmIcSy72DEIpTctnMEN1W34BGrnsDd5Xd/DKxKxHKTMCHtZRwLC2X0NWN"
  236. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMALVC8RDTHec+PC8y1s3tcpUAODgq6DEzQdHDf/cyvDMfmCaPiMxfIdmkns5lMa03hymIfSmLUF0jFFDc7biRp7uf9AAXNsrTmplHii0l0McuOOZGlSdZM4eL817P7UwJqFMxJyFXDjkubhQiX6kp25Kfuj/zLnupRCaiDvE7ho/xay6Jrv0XLz935TPDwkc7W1asLIvsZLheB+sRz9SMOb9gtrvk5WXZl5JTOFOLu+JaRwQLHL/xdcHJTOod7tqHYfpoC5JHrEwKzbhTOwxZBQBfTQjQktKENQtBxXHTe71rUEWfEZQGg60/BC4BrRmh4qJjlJu3v4VIhC7SSHn1"
  237. ];
  238. shell = pkgs.fish;
  239. };
  240. users.extraUsers.rj = {
  241. isNormalUser = true;
  242. extraGroups = ["wheel"];
  243. };
  244. users.extraUsers.backupdl = {
  245. isNormalUser = true;
  246. openssh.authorizedKeys.keys = [
  247. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyPk5WyFoWSvF4ozehxcVBoZ+UHgrI7VW/OoQfFFwIQe0qvetUZBMZwR2FwkLPAMZV8zz1v4EfncudEkVghy4P+/YVLlDjqDq9zwZnh8Nd/ifu84wmcNWHT2UcqnhjniCdshL8a44memzABnxfLLv+sXhP2x32cJAamo5y6fukr2qLp2jbXzR+3sv3klE0ruUXis/BR1lLqNJEYP8jB6fLn2sLKinnZPfn6DwVOk10mGeQsdME/eGl3phpjhODH9JW5V2V5nJBbC0rBnq+78dyArKVqjPSmIcSy72DEIpTctnMEN1W34BGrnsDd5Xd/DKxKxHKTMCHtZRwLC2X0NWN"
  248. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMALVC8RDTHec+PC8y1s3tcpUAODgq6DEzQdHDf/cyvDMfmCaPiMxfIdmkns5lMa03hymIfSmLUF0jFFDc7biRp7uf9AAXNsrTmplHii0l0McuOOZGlSdZM4eL817P7UwJqFMxJyFXDjkubhQiX6kp25Kfuj/zLnupRCaiDvE7ho/xay6Jrv0XLz935TPDwkc7W1asLIvsZLheB+sRz9SMOb9gtrvk5WXZl5JTOFOLu+JaRwQLHL/xdcHJTOod7tqHYfpoC5JHrEwKzbhTOwxZBQBfTQjQktKENQtBxXHTe71rUEWfEZQGg60/BC4BrRmh4qJjlJu3v4VIhC7SSHn1"
  249. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClMksJcVmUBeVbrnP2DceROvhpOpk7O3Ph6HpOwtL20Vimcr2mdWP+9oI3qcW34vDR6PWp/ZaaQga9F/sqWk2EsQilk6oZgiSr9VDts381H4SH0fqtXGpWaeM7/wNbFbNUff/ZNq0ZVKww2EFzffwjKzeKRtc9De1ABHY35AP/j2vHGTuqhdnePZDY8G+zGliS8uW2EXMKi6AVdk54FjlpW9KpcZxvKHCULvsLn+Gyw8d2bxu3BcpAjddDFHTXw+fW1hqavaYoHfs3C1vrq+bJwmxKv5bXfEmEK4y0uMn8RE6t0t32qtyqIiPF8TRBseEoe0jW2JEUEgCQzb2kK4KogWDSO+aV6dMIjRdFacOSKdjI41G96LaBtwHfd3/TOt5PJH6syl/J3BxEWRpQS9PFjDtgV87t0KKmiE6dqRJoVLl+acJj8FGPi2lZ+p5TFFCmgu9qag6Kh8bx+JErKZokHbB0obrSPxDjhZ5qsk1tpIEzWVzDowilgiv5ppdPI+M= backupdl@minipc"
  250. ];
  251. };
  252. users.extraUsers.occheung = {
  253. isNormalUser = true;
  254. extraGroups = ["lp" "scanner"];
  255. openssh.authorizedKeys.keys = [
  256. "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBPEvmWmxpFpMgp5fpjKud8ev0cyf/+X5fEpQt/YD/+u4mbvZYPE300DLqQ0h/qjgvaGMz1ndf4idYnRdy+plJEC/+hmlRW5NlcpAr3S/LYAisacgKToFVl+MlBo+emS9Ig=="
  257. ];
  258. };
  259. users.extraUsers.nix = {
  260. isNormalUser = true;
  261. };
  262. security.sudo.wheelNeedsPassword = false;
  263. boot.kernel.sysctl."kernel.dmesg_restrict" = true;
  264. services.udev.packages = [ pkgs.sane-backends ];
  265. nix.distributedBuilds = true;
  266. nix.nrBuildUsers = 64;
  267. nix.trustedUsers = ["sb"];
  268. services.hydra = {
  269. enable = true;
  270. package = pkgs.hydra-unstable;
  271. useSubstitutes = true;
  272. hydraURL = "https://nixbld.m-labs.hk";
  273. notificationSender = "hydra@m-labs.hk";
  274. minimumDiskFree = 15; # in GB
  275. minimumDiskFreeEvaluator = 1;
  276. extraConfig =
  277. ''
  278. binary_cache_secret_key_file = /etc/nixos/secret/nixbld.m-labs.hk-1
  279. max_output_size = 10000000000
  280. <runcommand>
  281. job = web:web:web
  282. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/web
  283. </runcommand>
  284. <runcommand>
  285. job = artiq:full:sipyco-manual-html
  286. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/sipyco-manual-html
  287. </runcommand>
  288. <runcommand>
  289. job = artiq:full:sipyco-manual-latexpdf
  290. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/sipyco-manual-latexpdf
  291. </runcommand>
  292. <runcommand>
  293. job = artiq:full-beta:artiq-manual-html
  294. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-html-beta
  295. </runcommand>
  296. <runcommand>
  297. job = artiq:full-beta:artiq-manual-latexpdf
  298. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-latexpdf-beta
  299. </runcommand>
  300. <runcommand>
  301. job = artiq:full-beta:conda-channel
  302. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-conda-channel-beta
  303. </runcommand>
  304. <runcommand>
  305. job = artiq:full:artiq-manual-html
  306. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-html
  307. </runcommand>
  308. <runcommand>
  309. job = artiq:full:artiq-manual-latexpdf
  310. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-latexpdf
  311. </runcommand>
  312. <runcommand>
  313. job = artiq:full:conda-channel
  314. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-conda-channel
  315. </runcommand>
  316. <runcommand>
  317. job = artiq:full-legacy:artiq-manual-html
  318. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-html-legacy
  319. </runcommand>
  320. <runcommand>
  321. job = artiq:full-legacy:artiq-manual-latexpdf
  322. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-latexpdf-legacy
  323. </runcommand>
  324. <runcommand>
  325. job = artiq:full-legacy:conda-channel
  326. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-conda-channel-legacy
  327. </runcommand>
  328. <runcommand>
  329. job = artiq:*:conda-channel
  330. command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-conda-channel-archives/$(jq -r '.build' < $HYDRA_JSON)
  331. </runcommand>
  332. <githubstatus>
  333. jobs = artiq:fast.*:extended-tests
  334. inputs = artiqSrc
  335. useShortContext = 1
  336. authorization = token ${(import /etc/nixos/secret/github_tokens.nix).artiq}
  337. </githubstatus>
  338. <gitea_authorization>
  339. sb=${(import /etc/nixos/secret/gitea_tokens.nix).artiq-zynq}
  340. </gitea_authorization>
  341. '';
  342. };
  343. systemd.services.hydra-www-outputs-init = {
  344. description = "Set up a hydra-owned directory for build outputs";
  345. wantedBy = [ "multi-user.target" ];
  346. requiredBy = [ "hydra-queue-runner.service" ];
  347. before = [ "hydra-queue-runner.service" ];
  348. serviceConfig = {
  349. Type = "oneshot";
  350. ExecStart = [
  351. "${pkgs.coreutils}/bin/mkdir -p ${hydraWwwOutputs} ${hydraWwwOutputs}/artiq-conda-channel-archives"
  352. "${pkgs.coreutils}/bin/chown hydra-queue-runner:hydra ${hydraWwwOutputs} ${hydraWwwOutputs}/artiq-conda-channel-archives"
  353. ];
  354. };
  355. };
  356. nix.extraOptions = ''
  357. secret-key-files = /etc/nixos/secret/nixbld.m-labs.hk-1
  358. '';
  359. nix.sandboxPaths = ["/opt"];
  360. services.munin-node.enable = true;
  361. services.munin-cron = {
  362. enable = true;
  363. hosts = ''
  364. [${config.networking.hostName}]
  365. address localhost
  366. '';
  367. };
  368. services.mlabs-backup.enable = true;
  369. services.ghbackup.enable = true;
  370. services.gitea = {
  371. enable = true;
  372. httpPort = 3001;
  373. rootUrl = "https://git.m-labs.hk/";
  374. appName = "M-Labs Git";
  375. cookieSecure = true;
  376. disableRegistration = true;
  377. mailerPasswordFile = "/etc/nixos/secret/mailerpassword";
  378. settings = {
  379. indexer = {
  380. REPO_INDEXER_ENABLED = true;
  381. };
  382. mailer = {
  383. ENABLED = true;
  384. HOST = "ssl.serverraum.org:587";
  385. FROM = "sysop@m-labs.hk";
  386. USER = "sysop@m-labs.hk";
  387. };
  388. service = {
  389. ENABLE_NOTIFY_MAIL = true;
  390. };
  391. attachment = {
  392. ALLOWED_TYPES = "*/*";
  393. };
  394. };
  395. };
  396. systemd.tmpfiles.rules = [
  397. "L+ '${config.services.gitea.stateDir}/custom/templates/home.tmpl' - - - - ${./gitea-home.tmpl}"
  398. "L+ '${config.services.gitea.stateDir}/custom/templates/user/auth/signin.tmpl' - - - - ${./gitea-signin.tmpl}"
  399. ];
  400. services.mattermost = {
  401. enable = true;
  402. siteUrl = "https://chat.m-labs.hk/";
  403. mutableConfig = true;
  404. };
  405. services.postgresql.package = pkgs.postgresql_11;
  406. services.matterbridge = {
  407. enable = true;
  408. configPath = "/etc/nixos/secret/matterbridge.toml";
  409. };
  410. nixpkgs.config.packageOverrides = super: let self = super.pkgs; in {
  411. nix = super.nix.overrideAttrs(oa: {
  412. patches = oa.patches or [] ++ [ ./nix-networked-derivations.diff ];
  413. });
  414. nixFlakes = super.nixFlakes.overrideAttrs(oa: {
  415. patches = oa.patches or [] ++ [ ./nix-3-networked-derivations.patch ];
  416. });
  417. hydra-unstable = super.hydra-unstable.overrideAttrs(oa: {
  418. patches = oa.patches or [] ++ [
  419. ./hydra-conda.patch
  420. ./hydra-restrictdist.patch
  421. ./hydra-hack-allowed-uris.patch # work around https://github.com/NixOS/nix/issues/5039
  422. ];
  423. hydraPath = oa.hydraPath + ":" + super.lib.makeBinPath [ super.jq ];
  424. });
  425. matterbridge = super.matterbridge.overrideAttrs(oa: {
  426. patches = oa.patches or [] ++ [ ./matterbridge-disable-github.patch ];
  427. });
  428. gitea = super.gitea.overrideAttrs(oa: {
  429. preBuild = let tagsString = "pam sqlite sqlite_unlock_notify"; in ''
  430. export buildFlagsArray=(
  431. -tags="${tagsString}"
  432. -ldflags='-X "main.Version=${oa.version}" -X "main.Tags=${tagsString}"'
  433. )
  434. '';
  435. });
  436. };
  437. security.acme.acceptTerms = true;
  438. security.acme.email = "sb" + "@m-labs.hk";
  439. security.acme.certs = {
  440. "nixbld.m-labs.hk" = {
  441. group = "nginx";
  442. webroot = "/var/lib/acme/acme-challenge";
  443. extraDomainNames = [
  444. "m-labs.hk"
  445. "www.m-labs.hk"
  446. "conda.m-labs.hk"
  447. "lab.m-labs.hk"
  448. "git.m-labs.hk"
  449. "chat.m-labs.hk"
  450. "hooks.m-labs.hk"
  451. "forum.m-labs.hk"
  452. "perso.m-labs.hk"
  453. "call.m-labs.hk"
  454. "rt.m-labs.hk"
  455. "nmigen.org"
  456. "www.nmigen.org"
  457. ];
  458. };
  459. };
  460. # https://github.com/NixOS/nixpkgs/issues/106862
  461. systemd.services."acme-fixperms".wants = [ "unbound.service" "dnsmasq.service" ];
  462. systemd.services."acme-fixperms".after = [ "unbound.service" "dnsmasq.service" ];
  463. services.nginx = {
  464. enable = true;
  465. recommendedProxySettings = true;
  466. recommendedGzipSettings = true;
  467. virtualHosts = let
  468. mainWebsite = {
  469. addSSL = true;
  470. useACMEHost = "nixbld.m-labs.hk";
  471. root = "${hydraWwwOutputs}/web";
  472. extraConfig = ''
  473. error_page 404 /404.html;
  474. '';
  475. locations."^~ /fonts/".extraConfig = ''
  476. expires 60d;
  477. '';
  478. locations."^~ /js/".extraConfig = ''
  479. expires 60d;
  480. '';
  481. locations."/MathJax/" = {
  482. alias = "/var/www/MathJax/";
  483. extraConfig = ''
  484. expires 60d;
  485. '';
  486. };
  487. # legacy URLs, redirect to avoid breaking people's bookmarks
  488. locations."/gateware.html".extraConfig = ''
  489. return 301 /gateware/migen/;
  490. '';
  491. locations."/migen".extraConfig = ''
  492. return 301 /gateware/migen/;
  493. '';
  494. locations."/artiq".extraConfig = ''
  495. return 301 /experiment-control/artiq/;
  496. '';
  497. locations."/artiq/resources.html".extraConfig = ''
  498. return 301 /experiment-control/resources/;
  499. '';
  500. # autogenerated manuals
  501. locations."/artiq/sipyco-manual/" = {
  502. alias = "${hydraWwwOutputs}/sipyco-manual-html/share/doc/sipyco-manual/html/";
  503. };
  504. locations."=/artiq/sipyco-manual.pdf" = {
  505. alias = "${hydraWwwOutputs}/sipyco-manual-latexpdf/share/doc/sipyco-manual/SiPyCo.pdf";
  506. };
  507. locations."/artiq/manual-beta/" = {
  508. alias = "${hydraWwwOutputs}/artiq-manual-html-beta/share/doc/artiq-manual/html/";
  509. };
  510. locations."=/artiq/manual-beta.pdf" = {
  511. alias = "${hydraWwwOutputs}/artiq-manual-latexpdf-beta/share/doc/artiq-manual/ARTIQ.pdf";
  512. };
  513. locations."/artiq/manual/" = {
  514. alias = "${hydraWwwOutputs}/artiq-manual-html/share/doc/artiq-manual/html/";
  515. };
  516. locations."=/artiq/manual.pdf" = {
  517. alias = "${hydraWwwOutputs}/artiq-manual-latexpdf/share/doc/artiq-manual/ARTIQ.pdf";
  518. };
  519. locations."/artiq/manual-legacy/" = {
  520. alias = "${hydraWwwOutputs}/artiq-manual-html-legacy/share/doc/artiq-manual/html/";
  521. };
  522. locations."=/artiq/manual-legacy.pdf" = {
  523. alias = "${hydraWwwOutputs}/artiq-manual-latexpdf-legacy/share/doc/artiq-manual/ARTIQ.pdf";
  524. };
  525. # legacy content
  526. locations."/migen/manual/" = {
  527. alias = "/var/www/m-labs.hk.old/migen/manual/";
  528. };
  529. locations."/artiq/manual-release-4/" = {
  530. alias = "/var/www/m-labs.hk.old/artiq/manual-release-4/";
  531. };
  532. locations."/artiq/manual-release-3/" = {
  533. alias = "/var/www/m-labs.hk.old/artiq/manual-release-3/";
  534. };
  535. locations."/artiq/manual-release-2/" = {
  536. alias = "/var/www/m-labs.hk.old/artiq/manual-release-2/";
  537. };
  538. };
  539. in {
  540. "m-labs.hk" = mainWebsite;
  541. "www.m-labs.hk" = mainWebsite;
  542. "lab.m-labs.hk" = {
  543. addSSL = true;
  544. useACMEHost = "nixbld.m-labs.hk";
  545. locations."/munin/".alias = "/var/www/munin/";
  546. locations."/munin".extraConfig = ''
  547. auth_basic "Munin";
  548. auth_basic_user_file /etc/nixos/secret/muninpasswd;
  549. '';
  550. };
  551. "nixbld.m-labs.hk" = {
  552. forceSSL = true;
  553. useACMEHost = "nixbld.m-labs.hk";
  554. locations."/".proxyPass = "http://127.0.0.1:3000";
  555. };
  556. "conda.m-labs.hk" = {
  557. forceSSL = true;
  558. useACMEHost = "nixbld.m-labs.hk";
  559. locations."/artiq-beta/" = {
  560. alias = "${hydraWwwOutputs}/artiq-conda-channel-beta/";
  561. extraConfig = ''
  562. autoindex on;
  563. index bogus_index_file;
  564. '';
  565. };
  566. locations."/artiq/" = {
  567. alias = "${hydraWwwOutputs}/artiq-conda-channel/";
  568. extraConfig = ''
  569. autoindex on;
  570. index bogus_index_file;
  571. '';
  572. };
  573. locations."/artiq-legacy/" = {
  574. alias = "${hydraWwwOutputs}/artiq-conda-channel-legacy/";
  575. extraConfig = ''
  576. autoindex on;
  577. index bogus_index_file;
  578. '';
  579. };
  580. locations."/artiq-archives/" = {
  581. alias = "${hydraWwwOutputs}/artiq-conda-channel-archives/";
  582. extraConfig = ''
  583. autoindex on;
  584. index bogus_index_file;
  585. '';
  586. };
  587. };
  588. "git.m-labs.hk" = {
  589. forceSSL = true;
  590. useACMEHost = "nixbld.m-labs.hk";
  591. locations."/".proxyPass = "http://127.0.0.1:3001";
  592. extraConfig = ''
  593. client_max_body_size 300M;
  594. '';
  595. };
  596. "chat.m-labs.hk" = {
  597. forceSSL = true;
  598. useACMEHost = "nixbld.m-labs.hk";
  599. locations."/".proxyPass = "http://127.0.0.1:8065";
  600. locations."~ /api/v[0-9]+/(users/)?websocket$".proxyPass = "http://127.0.0.1:8065";
  601. locations."~ /api/v[0-9]+/(users/)?websocket$".proxyWebsockets = true;
  602. };
  603. "hooks.m-labs.hk" = {
  604. forceSSL = true;
  605. useACMEHost = "nixbld.m-labs.hk";
  606. locations."/mattermost-github".extraConfig = ''
  607. include ${pkgs.nginx}/conf/uwsgi_params;
  608. uwsgi_pass unix:${config.services.uwsgi.runDir}/uwsgi-mgi.sock;
  609. '';
  610. locations."/rfq".extraConfig = ''
  611. include ${pkgs.nginx}/conf/uwsgi_params;
  612. uwsgi_pass unix:${config.services.uwsgi.runDir}/uwsgi-rfq.sock;
  613. '';
  614. };
  615. "forum.m-labs.hk" = {
  616. forceSSL = true;
  617. useACMEHost = "nixbld.m-labs.hk";
  618. root = "/var/www/flarum/public";
  619. locations."~ \.php$".extraConfig = ''
  620. fastcgi_pass unix:${config.services.phpfpm.pools.flarum.socket};
  621. fastcgi_index index.php;
  622. '';
  623. extraConfig = ''
  624. index index.php;
  625. include /var/www/flarum/.nginx.conf;
  626. '';
  627. };
  628. "call.m-labs.hk" = {
  629. useACMEHost = "nixbld.m-labs.hk";
  630. enableACME = false;
  631. forceSSL = true;
  632. };
  633. "perso.m-labs.hk" = {
  634. addSSL = true;
  635. useACMEHost = "nixbld.m-labs.hk";
  636. root = "/var/www/perso";
  637. };
  638. "rt.m-labs.hk" = {
  639. forceSSL = true;
  640. useACMEHost = "nixbld.m-labs.hk";
  641. locations."/" = {
  642. proxyPass = "http://127.0.0.1:4201";
  643. extraConfig = ''
  644. client_max_body_size 100M;
  645. '';
  646. };
  647. locations."/REST/1.0/NoAuth" = {
  648. proxyPass = "http://127.0.0.1:4201";
  649. extraConfig = ''
  650. client_max_body_size 100M;
  651. allow 127.0.0.1;
  652. deny all;
  653. '';
  654. };
  655. };
  656. "nmigen.org" = {
  657. addSSL = true;
  658. useACMEHost = "nixbld.m-labs.hk";
  659. locations."/".extraConfig = ''
  660. return 307 https://m-labs.hk/gateware/nmigen/;
  661. '';
  662. };
  663. "www.nmigen.org" = {
  664. addSSL = true;
  665. useACMEHost = "nixbld.m-labs.hk";
  666. locations."/".extraConfig = ''
  667. return 307 https://m-labs.hk/gateware/nmigen/;
  668. '';
  669. };
  670. };
  671. };
  672. services.uwsgi = {
  673. enable = true;
  674. plugins = [ "python3" ];
  675. instance = {
  676. type = "emperor";
  677. vassals = {
  678. mattermostgithub = import ./mattermost-github-integration/uwsgi-config.nix { inherit config pkgs; };
  679. rfq = import ./rfq/uwsgi-config.nix { inherit config pkgs; };
  680. };
  681. };
  682. };
  683. services.mysql = {
  684. enable = true;
  685. package = pkgs.mariadb;
  686. };
  687. services.phpfpm.pools.flarum = {
  688. user = "nobody";
  689. settings = {
  690. "listen.owner" = "nginx";
  691. "listen.group" = "nginx";
  692. "listen.mode" = "0600";
  693. "pm" = "dynamic";
  694. "pm.max_children" = 5;
  695. "pm.start_servers" = 2;
  696. "pm.min_spare_servers" = 1;
  697. "pm.max_spare_servers" = 3;
  698. "pm.max_requests" = 500;
  699. };
  700. };
  701. services.jitsi-meet = {
  702. enable = true;
  703. hostName = "call.m-labs.hk";
  704. };
  705. services.jitsi-videobridge.openFirewall = true;
  706. services.rt = {
  707. enable = true;
  708. package = pkgs.rt.overrideAttrs(oa: {
  709. patches = oa.patches or [] ++ [ ./rt-session.patch ];
  710. });
  711. organization = "M-Labs";
  712. domain = "rt.m-labs.hk";
  713. rtName = "Helpdesk";
  714. ownerEmail = "sb" + "@m-labs.hk";
  715. commentAddress = "helpdesk" + "@m-labs.hk";
  716. correspondAddress = "helpdesk" + "@m-labs.hk";
  717. sendmailPath = "${pkgs.msmtp}/bin/msmtp";
  718. sendmailArguments = ["-t" "-C" "/etc/nixos/secret/rt_msmtp.conf"];
  719. };
  720. systemd.services.rt-fetchmail = {
  721. description = "Fetchmail for RT";
  722. wantedBy = [ "multi-user.target" ];
  723. after = [ "network.target" ];
  724. serviceConfig = {
  725. Restart = "on-failure";
  726. User = "rt";
  727. Group = "rt";
  728. ExecStart = "${pkgs.bash}/bin/bash -c 'PATH=${pkgs.rt}/bin HOME=/tmp ${pkgs.fetchmail}/bin/fetchmail -f /etc/nixos/secret/rt_fetchmailrc'";
  729. };
  730. };
  731. system.stateVersion = "21.05";
  732. }