Merge branch 'merge-hectic-lab'
This commit is contained in:
@@ -11,7 +11,7 @@ let
|
||||
hectic.imports = attrValues (
|
||||
readModulesRecursive' ./hectic { inherit flake self inputs; }
|
||||
);
|
||||
# Read generic modules seperately
|
||||
# Read generic modules separately
|
||||
generic = readModulesRecursive'
|
||||
./generic
|
||||
{ inherit flake self inputs; };
|
||||
|
||||
169
nixos/module/generic/shadowsocks-rust.nix
Normal file
169
nixos/module/generic/shadowsocks-rust.nix
Normal file
@@ -0,0 +1,169 @@
|
||||
# INFO(nrv): This is standalone shadowsocks module. Instance-specific is at ./shadowsocks.nix
|
||||
{
|
||||
...
|
||||
}:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.shadowsocks-rust;
|
||||
|
||||
opts = {
|
||||
server = cfg.localAddress;
|
||||
server_port = cfg.port;
|
||||
method = cfg.encryptionMethod;
|
||||
mode = cfg.mode;
|
||||
user = "nobody";
|
||||
fast_open = cfg.fastOpen;
|
||||
} // optionalAttrs (cfg.plugin != null) {
|
||||
plugin = cfg.plugin;
|
||||
plugin_opts = cfg.pluginOpts;
|
||||
} // optionalAttrs (cfg.password != null) {
|
||||
password = cfg.password;
|
||||
} // cfg.extraConfig;
|
||||
|
||||
configFile = pkgs.writeText "shadowsocks.json" (builtins.toJSON opts);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.shadowsocks-rust = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = lib.mdDoc ''
|
||||
Whether to run shadowsocks-rust shadowsocks server.
|
||||
'';
|
||||
};
|
||||
|
||||
localAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "0.0.0.0";
|
||||
description = lib.mdDoc ''
|
||||
Local addresses to which the server binds.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8388;
|
||||
description = lib.mdDoc ''
|
||||
Port which the server uses.
|
||||
'';
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Password for connecting clients.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Password file with a password for connecting clients.
|
||||
'';
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = types.enum [ "tcp_only" "tcp_and_udp" "udp_only" ];
|
||||
default = "tcp_and_udp";
|
||||
description = lib.mdDoc ''
|
||||
Relay protocols.
|
||||
'';
|
||||
};
|
||||
|
||||
fastOpen = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc ''
|
||||
use TCP fast-open
|
||||
'';
|
||||
};
|
||||
|
||||
encryptionMethod = mkOption {
|
||||
type = types.str;
|
||||
default = "chacha20-ietf-poly1305";
|
||||
description = lib.mdDoc ''
|
||||
Encryption method. See <https://github.com/shadowsocks/shadowsocks-org/wiki/AEAD-Ciphers>.
|
||||
'';
|
||||
};
|
||||
|
||||
plugin = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = literalExpression ''"''${pkgs.shadowsocks-v2ray-plugin}/bin/v2ray-plugin"'';
|
||||
description = lib.mdDoc ''
|
||||
SIP003 plugin for shadowsocks
|
||||
'';
|
||||
};
|
||||
|
||||
pluginOpts = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "server;host=example.com";
|
||||
description = lib.mdDoc ''
|
||||
Options to pass to the plugin if one was specified
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = {
|
||||
nameserver = "8.8.8.8";
|
||||
};
|
||||
description = lib.mdDoc ''
|
||||
Additional configuration for shadowsocks that is not covered by the
|
||||
provided options. The provided attrset will be serialized to JSON and
|
||||
has to contain valid shadowsocks options. Unfortunately most
|
||||
additional options are undocumented but it's easy to find out what is
|
||||
available by looking into the source code of
|
||||
<https://github.com/shadowsocks/shadowsocks-rust/blob/master/src/jconf.c>
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = singleton
|
||||
{ assertion = cfg.password == null || cfg.passwordFile == null;
|
||||
message = "Cannot use both password and passwordFile for shadowsocks-rust";
|
||||
};
|
||||
|
||||
systemd.services.shadowsocks-rust = {
|
||||
description = "shadowsocks-rust Daemon";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.shadowsocks-rust ]
|
||||
++ optional (cfg.plugin != null) cfg.plugin
|
||||
++ optional (cfg.passwordFile != null) pkgs.jq;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
script = ''
|
||||
${optionalString (cfg.passwordFile != null) ''
|
||||
cat ${configFile} | jq --arg password "$(cat "${cfg.passwordFile}")" '. + { password: $password }' > /run/shadowsocks.json
|
||||
''}
|
||||
exec ssserver --config ${if cfg.passwordFile != null then "/run/shadowsocks.json" else configFile}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
28
nixos/module/generic/shadowsocks.nix
Normal file
28
nixos/module/generic/shadowsocks.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
...
|
||||
}:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
sops.secrets."ss-bfs/password" = {};
|
||||
services.shadowsocks-rust = {
|
||||
enable = true;
|
||||
plugin = "${pkgs.shadowsocks-v2ray-plugin}/bin/v2ray-plugin";
|
||||
# TODO: setup dnscrypt or a private DNS server for this
|
||||
# extraConfig = {
|
||||
# nameserver = "185.12.64.1"; # FIXME: this can vary across instances.
|
||||
# };
|
||||
port = 55228;
|
||||
pluginOpts = "server";
|
||||
# TODO: setup a TLS certs for this (look: (README.md) https://github.com/shadowsocks/v2ray-plugin/)
|
||||
#pluginOpts = "server;tls;host=ss.bfs.band";
|
||||
passwordFile = config.sops.secrets."ss-bfs/password".path;
|
||||
mode = "tcp_and_udp"; # default
|
||||
localAddress = "0.0.0.0";
|
||||
fastOpen = true; # default
|
||||
encryptionMethod = "chacha20-ietf-poly1305"; # default
|
||||
};
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
in {
|
||||
imports = [
|
||||
inputs.disko.nixosModules.default
|
||||
inputs.nixos-mailserver.nixosModules.mailserver
|
||||
];
|
||||
|
||||
options.hectic.archetype.base.enable = lib.mkEnableOption "Enable archetupe.dev";
|
||||
|
||||
65
nixos/module/hectic/service/mailserver.nix
Normal file
65
nixos/module/hectic/service/mailserver.nix
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
inputs,
|
||||
flake,
|
||||
self,
|
||||
}:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
cfg = config.services.mailserver;
|
||||
transformLoginAccounts = domain: input:
|
||||
builtins.listToAttrs (map (key: {
|
||||
name = key + "@" + domain;
|
||||
value = input.${key};
|
||||
}) (builtins.attrNames input));
|
||||
in {
|
||||
options = {
|
||||
services.mailserver.enable = lib.mkEnableOption "Mail server";
|
||||
|
||||
services.mailserver.domain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The domain name of the mail server";
|
||||
};
|
||||
|
||||
services.mailserver.loginAccounts = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule {
|
||||
options = {
|
||||
hashedPassword = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
};
|
||||
hashedPasswordFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Full path to a file containing the hashed password suitable
|
||||
for use with `chpasswd -e`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
description = "Login accounts for the mail server";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
mailserver = {
|
||||
enable = true;
|
||||
fqdn = "mail." + cfg.domain;
|
||||
domains = [ cfg.domain ];
|
||||
|
||||
loginAccounts = transformLoginAccounts cfg.domain cfg.loginAccounts;
|
||||
|
||||
certificateScheme = "acme-nginx";
|
||||
};
|
||||
|
||||
# NOTE(yukkop): avoid Gmail rejection due to missing IPv6 PTR records
|
||||
services.postfix.settings.main.inet_protocols = lib.mkDefault "ipv4";
|
||||
|
||||
security.acme.acceptTerms = true;
|
||||
security.acme.defaults.email = "security@" + cfg.domain;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user