1 { lib, pkgs, config, ... }:
3 package = pkgs.pure-ftpd.override { ldapFtpId = "immaeFtp"; };
4 pure-ftpd-enabled = config.myServices.ftp.pure-ftpd.enable;
5 proftpd-enabled = config.myServices.ftp.proftpd.enable;
9 myServices.ftp.enable = lib.mkOption {
10 type = lib.types.bool;
13 Whether to enable ftp.
16 myServices.ftp.pure-ftpd.enable = lib.mkOption {
17 type = lib.types.bool;
20 Whether to enable pure-ftpd.
23 myServices.ftp.proftpd.enable = lib.mkOption {
24 type = lib.types.bool;
27 Whether to enable proftpd.
32 config = lib.mkIf config.myServices.ftp.enable {
33 myServices.chatonsProperties.services.espace-de-stockage = {
34 file.datetime = "2022-08-22T01:00:00";
36 name = "Espace de stockage";
37 description = "Compte FTP/SFTP";
38 logo = if pure-ftpd-enabled
39 then "https://www.pureftpd.org/project/pure-ftpd/images/favicon.png"
40 else if proftpd-enabled
41 then "http://proftpd.org/proftpd.png"
43 website = "ftp.immae.eu";
45 status.description = "OK";
46 registration."" = ["MEMBER" "CLIENT"];
47 registration.load = "OPEN";
48 install.type = "PACKAGE";
50 software = if pure-ftpd-enabled then {
52 website = "https://www.pureftpd.org/project/pure-ftpd/";
53 license.url = "https://github.com/jedisct1/pure-ftpd/blob/master/COPYING";
54 license.name = "MIT Licence";
55 version = package.version;
56 source.url = "https://github.com/jedisct1/pure-ftpd/";
58 } else if proftpd-enabled then {
60 website = "http://proftpd.org/";
61 license.url = "https://github.com/proftpd/proftpd/blob/master/COPYING";
62 license.name = "GNU General Public License v2.0";
63 version = pkgs.proftpd.version;
64 source.url = "https://github.com/proftpd/proftpd/";
68 #myServices.chatonsProperties.services.ftp = {
69 # file.datetime = "2022-08-22T01:00:00";
71 # name = "Comptes FTP";
72 # description = "Compte FTP/SFTP";
73 # logo = if pure-ftpd-enabled
74 # then "https://www.pureftpd.org/project/pure-ftpd/images/favicon.png"
75 # else if proftpd-enabled
76 # then "http://proftpd.org/proftpd.png"
78 # website = "ftp.immae.eu";
79 # status.level = "OK";
80 # status.description = "OK";
81 # registration."" = ["MEMBER" "CLIENT"];
82 # registration.load = "OPEN";
83 # install.type = "PACKAGE";
85 # software = if pure-ftpd-enabled then {
87 # website = "https://www.pureftpd.org/project/pure-ftpd/";
88 # license.url = "https://github.com/jedisct1/pure-ftpd/blob/master/COPYING";
89 # license.name = "MIT Licence";
90 # version = package.version;
91 # source.url = "https://github.com/jedisct1/pure-ftpd/";
92 # } else if proftpd-enabled then {
94 # website = "http://proftpd.org/";
95 # license.url = "https://github.com/proftpd/proftpd/blob/master/COPYING";
96 # license.name = "GNU General Public License v2.0";
97 # version = pkgs.proftpd.version;
98 # source.url = "https://github.com/proftpd/proftpd/";
101 security.acme.certs."ftp" = config.myServices.certificates.certConfig // {
102 domain = "eldiron.immae.eu";
103 # FIXME: make it global
104 extraLegoRunFlags = ["--preferred-chain" "ISRG Root X1"];
105 extraLegoRenewFlags = ["--preferred-chain" "ISRG Root X1"];
106 postRun = (lib.optionalString pure-ftpd-enabled ''
107 systemctl restart pure-ftpd.service
108 '') + (lib.optionalString proftpd-enabled ''
109 systemctl restart proftpd.service
111 extraDomainNames = [ "ftp.immae.eu" ];
116 allowedTCPPorts = [ 21 115 ];
117 allowedTCPPortRanges = [ { from = 40000; to = 50000; } ];
122 uid = config.ids.uids.ftp; # 8
124 description = "Anonymous FTP user";
125 home = "/homeless-shelter";
126 extraGroups = [ "keys" ];
129 users.groups.ftp.gid = config.ids.gids.ftp;
131 system.activationScripts.ftp = ''
132 install -m 0755 -o ftp -g ftp -d /var/lib/ftp
133 '' + (lib.optionalString proftpd-enabled ''
134 install -m 0755 -o nobody -g nogroup -d /var/lib/proftpd/authorized_keys
137 secrets.keys."pure-ftpd-ldap" = lib.mkIf pure-ftpd-enabled {
138 permissions = "0400";
142 LDAPServer ${config.myEnv.ftp.ldap.host}
145 LDAPBaseDN ${config.myEnv.ftp.ldap.base}
146 LDAPBindDN ${config.myEnv.ftp.ldap.dn}
147 LDAPBindPW ${config.myEnv.ftp.ldap.password}
149 LDAPForceDefaultUID False
151 LDAPForceDefaultGID False
152 LDAPFilter ${config.myEnv.ftp.ldap.pure-ftpd_filter}
156 # Pas de possibilite de donner l'Uid/Gid !
157 # Compile dans pure-ftpd directement avec immaeFtpUid / immaeFtpGid
158 LDAPHomeDir immaeFtpDirectory
161 secrets.keys."proftpd-ldap.conf" = lib.mkIf proftpd-enabled {
162 permissions = "0400";
166 LDAPServer ldaps://${config.myEnv.ftp.ldap.host}:636/??sub
169 LDAPBindDN "${config.myEnv.ftp.ldap.dn}" "${config.myEnv.ftp.ldap.password}"
170 LDAPSearchScope subtree
174 LDAPForceDefaultUID off
175 LDAPForceDefaultGID off
176 LDAPAttr gidNumber immaeFtpGid
177 LDAPAttr uidNumber immaeFtpUid
178 LDAPAttr homeDirectory immaeFtpDirectory
179 LDAPUsers "${config.myEnv.ftp.ldap.base}" "${config.myEnv.ftp.ldap.proftpd_filter}"
180 LDAPGroups "${config.myEnv.ftp.ldap.base}"
184 services.filesWatcher.pure-ftpd = lib.mkIf pure-ftpd-enabled {
186 paths = [ config.secrets.fullPaths."pure-ftpd-ldap" ];
188 services.filesWatcher.proftpd = lib.mkIf proftpd-enabled {
190 paths = [ config.secrets.fullPaths."proftpd-ldap.conf" ];
193 systemd.services.pure-ftpd = let
194 configFile = pkgs.writeText "pure-ftpd.conf" ''
195 PassivePortRange 40000 50000
199 BrokenClientsCompatibility yes
210 LDAPConfigFile ${config.secrets.fullPaths."pure-ftpd-ldap"}
211 LimitRecursion 10000 8
212 AnonymousCanCreateDirs no
220 ProhibitDotFilesWrite no
221 ProhibitDotFilesRead no
223 AnonymousCantUpload no
227 CertFile ${config.security.acme.certs.ftp.directory}/full.pem
229 in lib.mkIf pure-ftpd-enabled {
230 description = "Pure-FTPd server";
231 wantedBy = [ "multi-user.target" ];
232 after = [ "network.target" ];
234 serviceConfig.ExecStart = "${package}/bin/pure-ftpd ${configFile}";
235 serviceConfig.Type = "forking";
236 serviceConfig.PIDFile = "/run/pure-ftpd.pid";
239 systemd.services.proftpd = let
240 configFile = pkgs.writeText "proftpd.conf" ''
242 ServerType standalone
252 # Set the user and group under which the server will run.
263 TLSProtocol TLSv1.1 TLSv1.2 TLSv1.3
265 TLSCertificateChainFile ${config.security.acme.certs.ftp.directory}/fullchain.pem
266 TLSECCertificateFile ${config.security.acme.certs.ftp.directory}/cert.pem
267 TLSECCertificateKeyFile ${config.security.acme.certs.ftp.directory}/key.pem
269 PidFile /run/proftpd/proftpd.pid
271 ScoreboardFile /run/proftpd/proftpd.scoreboard
273 PassivePorts 40000 50000
275 Include ${config.secrets.fullPaths."proftpd-ldap.conf"}
277 RequireValidShell off
279 # Bar use of SITE CHMOD by default
284 <VirtualHost 0.0.0.0>
293 SFTPHostKey /etc/ssh/ssh_host_ed25519_key
294 SFTPHostKey /etc/ssh/ssh_host_rsa_key
295 Include ${config.secrets.fullPaths."proftpd-ldap.conf"}
296 RequireValidShell off
297 SFTPAuthorizedUserKeys file:/var/lib/proftpd/authorized_keys/%u
298 SFTPAuthMethods password publickey
300 SFTPOptions IgnoreSFTPSetOwners
301 AllowChrootSymlinks off
304 in lib.mkIf proftpd-enabled {
305 description = "ProFTPD server";
306 wantedBy = [ "multi-user.target" ];
307 after = [ "network.target" ];
309 serviceConfig.ExecStart = "${pkgs.proftpd}/bin/proftpd -c ${configFile}";
310 serviceConfig.Type = "forking";
311 serviceConfig.PIDFile = "/run/proftpd/proftpd.pid";
312 serviceConfig.RuntimeDirectory = "proftpd";
315 services.cron.systemCronJobs = lib.mkIf proftpd-enabled [
316 "*/2 * * * * nobody ${./ftp_sync.sh}"