chore(koi): moved sftpgo to a docker container
This commit is contained in:
parent
26a33620bc
commit
e5897c194b
8 changed files with 186 additions and 263 deletions
|
@ -21,8 +21,8 @@
|
||||||
./services/landing
|
./services/landing
|
||||||
|
|
||||||
./containers/torrent.nix
|
./containers/torrent.nix
|
||||||
./containers/puffer.nix
|
|
||||||
./containers/vaultwarden.nix
|
./containers/vaultwarden.nix
|
||||||
|
./containers/sftpgo
|
||||||
./containers/verdaccio
|
./containers/verdaccio
|
||||||
./containers/sharkey
|
./containers/sharkey
|
||||||
./containers/pds
|
./containers/pds
|
||||||
|
|
|
@ -1,210 +0,0 @@
|
||||||
{ abs, lib, config, pkgs, ... }@inputs:
|
|
||||||
|
|
||||||
let
|
|
||||||
containers = import (abs "lib/containers.nix") inputs;
|
|
||||||
avahi = import (abs "lib/avahi.nix") inputs;
|
|
||||||
systemd = import (abs "lib/systemd.nix") inputs;
|
|
||||||
sftpgo = import (abs "services/sftpgo.nix") inputs;
|
|
||||||
secrets = import (abs "lib/secrets.nix");
|
|
||||||
|
|
||||||
sftpKey = secrets.mount config "sftpgo-ed25519";
|
|
||||||
|
|
||||||
sambaConfig = {
|
|
||||||
imports = [
|
|
||||||
(systemd.mkOneshot {
|
|
||||||
name = "smb-guest-setup";
|
|
||||||
# for whatever reason smbd refuses to write unless we set the password
|
|
||||||
script = "${pkgs.samba}/bin/smbpasswd -a smb-guest -n";
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
services.samba = {
|
|
||||||
enable = true;
|
|
||||||
openFirewall = true;
|
|
||||||
|
|
||||||
securityType = "user";
|
|
||||||
extraConfig = ''
|
|
||||||
workgroup = WORKGROUP
|
|
||||||
server string = puffer
|
|
||||||
netbios name = puffer
|
|
||||||
security = user
|
|
||||||
hosts allow = 10.0.0.0/8
|
|
||||||
hosts deny = 0.0.0.0/0
|
|
||||||
guest account = smb-guest
|
|
||||||
map to guest = bad user
|
|
||||||
inherit permissions = yes
|
|
||||||
|
|
||||||
# Performance
|
|
||||||
socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=131072 SO_SNDBUF=131072
|
|
||||||
read raw = yes
|
|
||||||
write raw = yes
|
|
||||||
server signing = no
|
|
||||||
strict locking = no
|
|
||||||
min receivefile size = 16384
|
|
||||||
use sendfile = Yes
|
|
||||||
aio read size = 16384
|
|
||||||
aio write size = 16384
|
|
||||||
|
|
||||||
# Fruit global config
|
|
||||||
fruit:aapl = yes
|
|
||||||
fruit:nfs_aces = no
|
|
||||||
fruit:copyfile = no
|
|
||||||
fruit:model = MacSamba
|
|
||||||
'';
|
|
||||||
|
|
||||||
shares =
|
|
||||||
let
|
|
||||||
publicShare = {
|
|
||||||
browseable = "yes";
|
|
||||||
"read only" = "no";
|
|
||||||
"guest ok" = "yes";
|
|
||||||
"create mask" = "2775";
|
|
||||||
"directory mask" = "2775";
|
|
||||||
"force user" = "smb-guest";
|
|
||||||
"force group" = "puffer";
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
Downloads = {
|
|
||||||
path = "/mnt/puffer/Downloads";
|
|
||||||
browseable = "yes";
|
|
||||||
"read only" = "yes";
|
|
||||||
"guest ok" = "yes";
|
|
||||||
};
|
|
||||||
|
|
||||||
Public = publicShare // {
|
|
||||||
path = "/mnt/puffer/Public";
|
|
||||||
};
|
|
||||||
|
|
||||||
# its ok for this to be local-public, since Time Machine
|
|
||||||
# backups are to be encrypted anyway
|
|
||||||
# (and also im too lazy to set up users here)
|
|
||||||
Backups = publicShare // {
|
|
||||||
path = "/mnt/puffer/Backups";
|
|
||||||
# whatever this means
|
|
||||||
"vfs objects" = "catia fruit streams_xattr";
|
|
||||||
"fruit:time machine" = "yes";
|
|
||||||
"fruit:time machine max size" = "100G";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
avahiConfig = avahi.setup {
|
|
||||||
name = "puffer";
|
|
||||||
services = [
|
|
||||||
{ type = "_smb._tcp"; port = 445; }
|
|
||||||
# cancer stuff for macs to see this disk as a time machine-compatible disk
|
|
||||||
[
|
|
||||||
{ type = "_adisk._tcp"; port = 9; }
|
|
||||||
{ txt-record = "sys=waMa=0,adVF=0x100"; }
|
|
||||||
{ txt-record = "dk0=adVN=Puffer TimeMachine,adVF=0x82"; }
|
|
||||||
]
|
|
||||||
{ type = "_device-info._tcp"; port = 0; txt-record = "model=TimeCapsule8,119"; }
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
sftpgoConfig = sftpgo.setup {
|
|
||||||
package = pkgs.callPackage (abs "packages/sftpgo.nix") {
|
|
||||||
tags = [ "nogcs" "nos3" "noazblob" "nobolt" "nomysql" "nopgsql" "nometrics" "bundle" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
sftpd = {
|
|
||||||
bindings = [
|
|
||||||
{ port = 22; }
|
|
||||||
];
|
|
||||||
host_keys = [ "id_ed25519" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
keys.ed25519 = sftpKey.path;
|
|
||||||
|
|
||||||
users.guest = {
|
|
||||||
# bcrypt-hashed 0
|
|
||||||
password = "$2a$10$IcGdNtx10ycmPRD6lA4c0uNfRXTEchFRzCZEDkngTjzForn6pd0Wa";
|
|
||||||
};
|
|
||||||
|
|
||||||
folders.Public.path = "/mnt/puffer/Public";
|
|
||||||
folders.Downloads.path = "/mnt/puffer/Downloads";
|
|
||||||
|
|
||||||
usersFolders = [
|
|
||||||
{ username = "guest"; folder = "Public"; }
|
|
||||||
{ username = "guest"; folder = "Downloads"; }
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
container = containers.mkNixosContainer {
|
|
||||||
name = "puffer";
|
|
||||||
ip = "10.42.0.5";
|
|
||||||
private = false;
|
|
||||||
|
|
||||||
config = { ... }: {
|
|
||||||
imports = [
|
|
||||||
sambaConfig
|
|
||||||
avahiConfig
|
|
||||||
sftpgoConfig
|
|
||||||
];
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
uxplay
|
|
||||||
];
|
|
||||||
|
|
||||||
users.groups.puffer = { };
|
|
||||||
users.users.smb-guest = {
|
|
||||||
isNormalUser = true;
|
|
||||||
description = "Guest account for Samba";
|
|
||||||
extraGroups = [ "puffer" ];
|
|
||||||
createHome = false;
|
|
||||||
shell = pkgs.shadow;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d /mnt/puffer/Public 0755 smb-guest puffer - -"
|
|
||||||
"d /mnt/puffer/Backups 0755 smb-guest puffer - -"
|
|
||||||
];
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 22 7000 7001 7002 ];
|
|
||||||
networking.firewall.allowedUDPPorts = [ 22 7000 7001 7002 ];
|
|
||||||
};
|
|
||||||
|
|
||||||
mounts = {
|
|
||||||
"/mnt/puffer" = {
|
|
||||||
hostPath = "/mnt/puffer";
|
|
||||||
isReadOnly = false;
|
|
||||||
};
|
|
||||||
} // (sftpKey.mounts);
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
(secrets.declare [ "sftpgo-ed25519" ])
|
|
||||||
container
|
|
||||||
];
|
|
||||||
|
|
||||||
services.nginx.virtualHosts."puffer.stupid.fish" = {
|
|
||||||
forceSSL = true;
|
|
||||||
useACMEHost = "stupid.fish";
|
|
||||||
|
|
||||||
locations."/public/" = {
|
|
||||||
extraConfig = ''
|
|
||||||
alias /mnt/puffer/Public/;
|
|
||||||
autoindex on;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
locations."/downloads/" = {
|
|
||||||
extraConfig = ''
|
|
||||||
alias /mnt/puffer/Downloads/;
|
|
||||||
autoindex on;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
locations."= /" = {
|
|
||||||
extraConfig = ''
|
|
||||||
add_header 'Content-Type' 'text/html; charset=utf-8';
|
|
||||||
return 200 '<html><body><h1>🐡 puffer</h1><a href="/public/">public</a><br><a href="/downloads/">downloads</a></body></html>';
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
68
hosts/koi/containers/sftpgo/default.nix
Normal file
68
hosts/koi/containers/sftpgo/default.nix
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
{ pkgs, abs, config, ... }@inputs:
|
||||||
|
|
||||||
|
let
|
||||||
|
secrets = import (abs "lib/secrets.nix");
|
||||||
|
|
||||||
|
UID = 1112;
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
(secrets.declare [{
|
||||||
|
name = "sftpgo-env";
|
||||||
|
owner = "sftpgo";
|
||||||
|
}])
|
||||||
|
./samba.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
users.users.sftpgo = {
|
||||||
|
isNormalUser = true;
|
||||||
|
uid = UID;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualisation.oci-containers.containers.sftpgo = {
|
||||||
|
image = "drakkan/sftpgo:v2.6.2";
|
||||||
|
volumes = [
|
||||||
|
"/srv/sftpgo/data:/srv/sftpgo"
|
||||||
|
"/srv/sftpgo/config:/var/lib/sftpgo"
|
||||||
|
"/mnt/puffer:/mnt/puffer"
|
||||||
|
];
|
||||||
|
user = builtins.toString UID;
|
||||||
|
environment = {
|
||||||
|
SFTPGO_SFTPD__BINDINGS__0__PORT = "22";
|
||||||
|
SFTPGO_WEBDAVD__BINDINGS__0__PORT = "80";
|
||||||
|
SFTPGO_WEBDAVD__BINDINGS__0__PROXY_ALLOWED = "172.17.0.1";
|
||||||
|
SFTPGO_WEBDAVD__BINDINGS__0__CLIENT_IP_PROXY_HEADER = "X-Forwarded-For";
|
||||||
|
SFTPGO_WEBDAVD__BINDINGS__0__PREFIX = "/dav/";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__PORT = "8080";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__ENABLED_LOGIN_METHODS = "3";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__SECURITY__ENABLED = "true";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__SECURITY__ALLOWED_HOSTS = "puffer.stupid.fish";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__BRANDING__NAME = "puffer";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__BRANDING__SHORT_NAME = "puffer";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__OIDC__REDIRECT_BASE_URL = "https://puffer.stupid.fish/";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__OIDC__USERNAME_FIELD = "preferred_username";
|
||||||
|
SFTPGO_HTTPD__BINDINGS__0__OIDC__IMPLICIT_ROLES = "true";
|
||||||
|
};
|
||||||
|
environmentFiles = [
|
||||||
|
(secrets.file config "sftpgo-env")
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /srv/sftpgo/data 0700 ${builtins.toString UID} ${builtins.toString UID} -"
|
||||||
|
"d /srv/sftpgo/config 0700 ${builtins.toString UID} ${builtins.toString UID} -"
|
||||||
|
];
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."puffer.stupid.fish" = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "stupid.fish";
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://sftpgo.docker:8080$request_uri";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
locations."/dav/" = {
|
||||||
|
proxyPass = "http://sftpgo.docker:80$request_uri";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
116
hosts/koi/containers/sftpgo/samba.nix
Normal file
116
hosts/koi/containers/sftpgo/samba.nix
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
{ abs, lib, config, pkgs, ... }@inputs:
|
||||||
|
|
||||||
|
let
|
||||||
|
containers = import (abs "lib/containers.nix") inputs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(containers.mkNixosContainer {
|
||||||
|
name = "puffer";
|
||||||
|
ip = "10.42.0.5";
|
||||||
|
private = false;
|
||||||
|
|
||||||
|
config = { ... }: {
|
||||||
|
users.users.smb-guest.isNormalUser = true;
|
||||||
|
|
||||||
|
services.avahi = {
|
||||||
|
enable = true;
|
||||||
|
nssmdns4 = true;
|
||||||
|
openFirewall = true;
|
||||||
|
publish = {
|
||||||
|
enable = true;
|
||||||
|
userServices = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
extraServiceFiles.puffer = ''
|
||||||
|
<?xml version="1.0" standalone='no'?>
|
||||||
|
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||||
|
<service-group>
|
||||||
|
<name>puffer</name>
|
||||||
|
<service>
|
||||||
|
<port>445</port>
|
||||||
|
<type>_smb._tcp</type>
|
||||||
|
</service>
|
||||||
|
<service>
|
||||||
|
<port>9</port>
|
||||||
|
<type>_adisk._tcp</type>
|
||||||
|
<txt-record>sys=waMa=0,adVF=0x100</txt-record>
|
||||||
|
<txt-record>dk0=adVN=Puffer TimeMachine,adVF=0x82</txt-record>
|
||||||
|
</service>
|
||||||
|
<service>
|
||||||
|
<port>0</port>
|
||||||
|
<type>_device-info._tcp</type>
|
||||||
|
<txt-record>model=TimeCapsule8,119</txt-record>
|
||||||
|
</service>
|
||||||
|
</service-group>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.samba = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
|
||||||
|
securityType = "user";
|
||||||
|
extraConfig = ''
|
||||||
|
workgroup = WORKGROUP
|
||||||
|
server string = puffer
|
||||||
|
netbios name = puffer
|
||||||
|
security = user
|
||||||
|
guest account = smb-guest
|
||||||
|
map to guest = bad user
|
||||||
|
hosts allow = 10.0.0.0/8
|
||||||
|
hosts deny = 0.0.0.0/0
|
||||||
|
inherit permissions = yes
|
||||||
|
|
||||||
|
# Performance
|
||||||
|
socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=131072 SO_SNDBUF=131072
|
||||||
|
read raw = yes
|
||||||
|
write raw = yes
|
||||||
|
server signing = no
|
||||||
|
strict locking = no
|
||||||
|
min receivefile size = 16384
|
||||||
|
use sendfile = Yes
|
||||||
|
aio read size = 16384
|
||||||
|
aio write size = 16384
|
||||||
|
|
||||||
|
# Fruit global config
|
||||||
|
fruit:aapl = yes
|
||||||
|
fruit:nfs_aces = no
|
||||||
|
fruit:copyfile = no
|
||||||
|
fruit:model = MacSamba
|
||||||
|
'';
|
||||||
|
|
||||||
|
shares =
|
||||||
|
let
|
||||||
|
common = {
|
||||||
|
browseable = "yes";
|
||||||
|
"read only" = "yes";
|
||||||
|
"guest ok" = "yes";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
Downloads = common // {
|
||||||
|
path = "/mnt/puffer/Downloads";
|
||||||
|
};
|
||||||
|
|
||||||
|
Public = common // {
|
||||||
|
path = "/mnt/puffer/Public";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mounts = {
|
||||||
|
"/mnt/puffer/Downloads" = {
|
||||||
|
hostPath = "/mnt/puffer/Downloads";
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
"/mnt/puffer/Public" = {
|
||||||
|
hostPath = "/mnt/puffer/Public";
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ let
|
||||||
10.42.0.2 very.stupid.fish
|
10.42.0.2 very.stupid.fish
|
||||||
10.42.0.8 bnuuy.stupid.fish
|
10.42.0.8 bnuuy.stupid.fish
|
||||||
10.42.0.2 puffer.stupid.fish
|
10.42.0.2 puffer.stupid.fish
|
||||||
|
10.42.0.2 puffer-webdav.stupid.fish
|
||||||
'';
|
'';
|
||||||
|
|
||||||
package = coredns.override {
|
package = coredns.override {
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
{ ... }@inputs:
|
|
||||||
|
|
||||||
let
|
|
||||||
xml = import ./xml.nix;
|
|
||||||
in
|
|
||||||
rec {
|
|
||||||
mkConfig = config:
|
|
||||||
let
|
|
||||||
configs = if builtins.isList config then config else [ config ];
|
|
||||||
data = map
|
|
||||||
(cfg: {
|
|
||||||
service-group =
|
|
||||||
[{ name = cfg.name; }] ++
|
|
||||||
map (service: { inherit service; }) cfg.services ++
|
|
||||||
[ cfg.extra or { } ];
|
|
||||||
})
|
|
||||||
configs;
|
|
||||||
in
|
|
||||||
''
|
|
||||||
<?xml version="1.0" standalone='no'?>
|
|
||||||
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
|
||||||
${xml.generateXMLInner { obj = data; }}
|
|
||||||
'';
|
|
||||||
|
|
||||||
setup = services:
|
|
||||||
let
|
|
||||||
servicesList = if builtins.isList services then services else [ services ];
|
|
||||||
in
|
|
||||||
{
|
|
||||||
services.avahi = {
|
|
||||||
enable = true;
|
|
||||||
nssmdns4 = true;
|
|
||||||
openFirewall = true;
|
|
||||||
publish = {
|
|
||||||
enable = true;
|
|
||||||
userServices = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
extraServiceFiles = (builtins.listToAttrs (map
|
|
||||||
(service: {
|
|
||||||
name = service.name;
|
|
||||||
value = mkConfig service;
|
|
||||||
})
|
|
||||||
servicesList));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
age-encryption.org/v1
|
|
||||||
-> ssh-ed25519 sj88Xw 2YLa2A0IPI5OYU1pACLEZmIXse0w3rwthY/0IhUfITE
|
|
||||||
W3fHzNoxCouKZXeEZpfZTAfIAKIF07rCDvvnNHgF23Y
|
|
||||||
--- dIuhxlxaabb+kOpULhF3wcj6CaDpjnLCdog9dTnsWyo
|
|
||||||
%Å0ÕÛE~G öZ^UFR‘”ji©w/Ö‘ÄCM~þv©«AŠdá>[h´ëAÁÊÆãÊ¿œV>D>[m?€y–£CZ©Ù^yĹ˜TP§“Ó<ÖDL¡Î£âFÞ©³Ld<4C>éÏ
j1(¸A¢(êõ7ë-î§
<0A>}“°JQ4¦EÝÍ›î%'ìªí/‹
|
|
BIN
secrets/sftpgo-env.age
Normal file
BIN
secrets/sftpgo-env.age
Normal file
Binary file not shown.
Loading…
Reference in a new issue