2022-04-27 09:35:20 +00:00
{ config , lib , pkgs , utils , . . . }:
2020-04-24 23:36:52 +00:00
with lib ;
let
2022-10-06 18:32:54 +00:00
cfg = config . services . kubo ;
2020-04-24 23:36:52 +00:00
2022-10-06 18:32:54 +00:00
kuboFlags = utils . escapeSystemdExecArgs (
2022-03-30 09:31:56 +00:00
optional cfg . autoMount " - - m o u n t " ++
optional cfg . enableGC " - - e n a b l e - g c " ++
optional ( cfg . serviceFdlimit != null ) " - - m a n a g e - f d l i m i t = f a l s e " ++
optional ( cfg . defaultMode == " o f f l i n e " ) " - - o f f l i n e " ++
optional ( cfg . defaultMode == " n o r o u t i n g " ) " - - r o u t i n g = n o n e " ++
cfg . extraFlags
) ;
2020-04-24 23:36:52 +00:00
2021-09-18 10:52:07 +00:00
profile =
if cfg . localDiscovery
then " l o c a l - d i s c o v e r y "
else " s e r v e r " ;
2020-06-15 15:56:04 +00:00
splitMulitaddr = addrRaw : lib . tail ( lib . splitString " / " addrRaw ) ;
2021-09-18 10:52:07 +00:00
multiaddrToListenStream = addrRaw :
let
2020-06-15 15:56:04 +00:00
addr = splitMulitaddr addrRaw ;
s = builtins . elemAt addr ;
2021-09-18 10:52:07 +00:00
in
if s 0 == " i p 4 " && s 2 == " t c p "
then " ${ s 1 } : ${ s 3 } "
2020-06-15 15:56:04 +00:00
else if s 0 == " i p 6 " && s 2 == " t c p "
2021-09-18 10:52:07 +00:00
then " [ ${ s 1 } ] : ${ s 3 } "
2020-06-15 15:56:04 +00:00
else if s 0 == " u n i x "
2021-09-18 10:52:07 +00:00
then " / ${ lib . concatStringsSep " / " ( lib . tail addr ) } "
2020-06-15 15:56:04 +00:00
else null ; # not valid for listen stream, skip
2021-09-18 10:52:07 +00:00
multiaddrToListenDatagram = addrRaw :
let
2020-08-20 17:08:02 +00:00
addr = splitMulitaddr addrRaw ;
s = builtins . elemAt addr ;
2021-09-18 10:52:07 +00:00
in
if s 0 == " i p 4 " && s 2 == " u d p "
then " ${ s 1 } : ${ s 3 } "
2020-08-20 17:08:02 +00:00
else if s 0 == " i p 6 " && s 2 == " u d p "
2021-09-18 10:52:07 +00:00
then " [ ${ s 1 } ] : ${ s 3 } "
2020-08-20 17:08:02 +00:00
else null ; # not valid for listen datagram, skip
2021-09-18 10:52:07 +00:00
in
{
2020-04-24 23:36:52 +00:00
###### interface
options = {
2022-10-06 18:32:54 +00:00
services . kubo = {
2020-04-24 23:36:52 +00:00
2022-09-09 14:08:57 +00:00
enable = mkEnableOption ( lib . mdDoc " I n t e r p l a n e t a r y F i l e S y s t e m ( W A R N I N G : m a y c a u s e s e v e r e n e t w o r k d e g r e d a t i o n ) " ) ;
2020-04-24 23:36:52 +00:00
2020-11-06 00:33:48 +00:00
package = mkOption {
type = types . package ;
2022-10-06 18:32:54 +00:00
default = pkgs . kubo ;
defaultText = literalExpression " p k g s . k u b o " ;
description = lib . mdDoc " W h i c h K u b o p a c k a g e t o u s e . " ;
2020-11-06 00:33:48 +00:00
} ;
2020-04-24 23:36:52 +00:00
user = mkOption {
type = types . str ;
default = " i p f s " ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " U s e r u n d e r w h i c h t h e K u b o d a e m o n r u n s " ;
2020-04-24 23:36:52 +00:00
} ;
group = mkOption {
type = types . str ;
default = " i p f s " ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " G r o u p u n d e r w h i c h t h e K u b o d a e m o n r u n s " ;
2020-04-24 23:36:52 +00:00
} ;
dataDir = mkOption {
type = types . str ;
2021-09-18 10:52:07 +00:00
default =
if versionAtLeast config . system . stateVersion " 1 7 . 0 9 "
then " / v a r / l i b / i p f s "
else " / v a r / l i b / i p f s / . i p f s " ;
2021-12-06 16:07:01 +00:00
defaultText = literalExpression ''
if versionAtLeast config . system . stateVersion " 1 7 . 0 9 "
then " / v a r / l i b / i p f s "
else " / v a r / l i b / i p f s / . i p f s "
'' ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " T h e d a t a d i r f o r K u b o " ;
2020-04-24 23:36:52 +00:00
} ;
defaultMode = mkOption {
type = types . enum [ " o n l i n e " " o f f l i n e " " n o r o u t i n g " ] ;
default = " o n l i n e " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " s y s t e m d s e r v i c e t h a t i s e n a b l e d b y d e f a u l t " ;
2020-04-24 23:36:52 +00:00
} ;
autoMount = mkOption {
type = types . bool ;
default = false ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " W h e t h e r K u b o s h o u l d t r y t o m o u n t / i p f s a n d / i p n s a t s t a r t u p . " ;
2020-04-24 23:36:52 +00:00
} ;
2021-09-18 10:52:07 +00:00
autoMigrate = mkOption {
type = types . bool ;
default = true ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " W h e t h e r K u b o s h o u l d t r y t o r u n t h e f s - r e p o - m i g r a t i o n a t s t a r t u p . " ;
2021-09-18 10:52:07 +00:00
} ;
2020-04-24 23:36:52 +00:00
ipfsMountDir = mkOption {
type = types . str ;
default = " / i p f s " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " W h e r e t o m o u n t t h e I P F S n a m e s p a c e t o " ;
2020-04-24 23:36:52 +00:00
} ;
ipnsMountDir = mkOption {
type = types . str ;
default = " / i p n s " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " W h e r e t o m o u n t t h e I P N S n a m e s p a c e t o " ;
2020-04-24 23:36:52 +00:00
} ;
gatewayAddress = mkOption {
type = types . str ;
default = " / i p 4 / 1 2 7 . 0 . 0 . 1 / t c p / 8 0 8 0 " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " W h e r e t h e I P F S G a t e w a y c a n b e r e a c h e d " ;
2020-04-24 23:36:52 +00:00
} ;
apiAddress = mkOption {
type = types . str ;
default = " / i p 4 / 1 2 7 . 0 . 0 . 1 / t c p / 5 0 0 1 " ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " W h e r e K u b o e x p o s e s i t s A P I t o " ;
2020-04-24 23:36:52 +00:00
} ;
swarmAddress = mkOption {
type = types . listOf types . str ;
2020-06-15 15:56:04 +00:00
default = [
" / i p 4 / 0 . 0 . 0 . 0 / t c p / 4 0 0 1 "
" / i p 6 / : : / t c p / 4 0 0 1 "
2020-08-20 17:08:02 +00:00
" / i p 4 / 0 . 0 . 0 . 0 / u d p / 4 0 0 1 / q u i c "
" / i p 6 / : : / u d p / 4 0 0 1 / q u i c "
2020-06-15 15:56:04 +00:00
] ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " W h e r e K u b o l i s t e n s f o r i n c o m i n g p 2 p c o n n e c t i o n s " ;
2020-04-24 23:36:52 +00:00
} ;
enableGC = mkOption {
type = types . bool ;
default = false ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " W h e t h e r t o e n a b l e a u t o m a t i c g a r b a g e c o l l e c t i o n " ;
2020-04-24 23:36:52 +00:00
} ;
emptyRepo = mkOption {
type = types . bool ;
default = false ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " I f s e t t o t r u e , t h e r e p o w o n ' t b e i n i t i a l i z e d w i t h h e l p f i l e s " ;
2020-04-24 23:36:52 +00:00
} ;
extraConfig = mkOption {
type = types . attrs ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc ''
Attrset of daemon configuration to set using { command } ` ipfs config ` , every time the daemon starts .
2020-04-24 23:36:52 +00:00
These are applied last , so may override configuration set by other options in this module .
Keep in mind that this configuration is stateful ; i . e . , unsetting anything in here does not reset the value to the default !
'' ;
2021-09-18 10:52:07 +00:00
default = { } ;
2020-04-24 23:36:52 +00:00
example = {
Datastore . StorageMax = " 1 0 0 G B " ;
Discovery . MDNS . Enabled = false ;
Bootstrap = [
" / i p 4 / 1 2 8 . 1 9 9 . 2 1 9 . 1 1 1 / t c p / 4 0 0 1 / i p f s / Q m S o L S a f T M B s P K a d T E g a X c t D Q V c q N 8 8 C N L H X M k T N w M K P n u "
" / i p 4 / 1 6 2 . 2 4 3 . 2 4 8 . 2 1 3 / t c p / 4 0 0 1 / i p f s / Q m S o L u e R 4 x B e U b Y 9 W Z 9 x G U U x u n b K W c r N F T D A a d Q J m o c n W m "
] ;
Swarm . AddrFilters = null ;
} ;
} ;
extraFlags = mkOption {
type = types . listOf types . str ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " E x t r a f l a g s p a s s e d t o t h e K u b o d a e m o n " ;
2021-09-18 10:52:07 +00:00
default = [ ] ;
2020-04-24 23:36:52 +00:00
} ;
localDiscovery = mkOption {
type = types . bool ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc '' W h e t h e r t o e n a b l e l o c a l d i s c o v e r y f o r t h e K u b o d a e m o n .
This will allow Kubo to scan ports on your local network . Some hosting services will ban you if you do this .
2020-04-24 23:36:52 +00:00
'' ;
2021-09-18 10:52:07 +00:00
default = false ;
2020-04-24 23:36:52 +00:00
} ;
serviceFdlimit = mkOption {
type = types . nullOr types . int ;
default = null ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " T h e f d l i m i t f o r t h e K u b o s y s t e m d u n i t o r ` n u l l ` t o h a v e t h e d a e m o n a t t e m p t t o m a n a g e i t " ;
2021-09-18 10:52:07 +00:00
example = 64 * 1024 ;
2020-04-24 23:36:52 +00:00
} ;
2020-06-18 07:06:33 +00:00
startWhenNeeded = mkOption {
type = types . bool ;
default = false ;
2022-10-06 18:32:54 +00:00
description = lib . mdDoc " W h e t h e r t o u s e s o c k e t a c t i v a t i o n t o s t a r t K u b o w h e n n e e d e d . " ;
2020-06-18 07:06:33 +00:00
} ;
2020-04-24 23:36:52 +00:00
} ;
} ;
###### implementation
config = mkIf cfg . enable {
2020-11-06 00:33:48 +00:00
environment . systemPackages = [ cfg . package ] ;
2020-06-18 07:06:33 +00:00
environment . variables . IPFS_PATH = cfg . dataDir ;
2021-09-18 10:52:07 +00:00
# https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size
boot . kernel . sysctl . " n e t . c o r e . r m e m _ m a x " = mkDefault 2500000 ;
2020-04-24 23:36:52 +00:00
programs . fuse = mkIf cfg . autoMount {
userAllowOther = true ;
} ;
users . users = mkIf ( cfg . user == " i p f s " ) {
ipfs = {
group = cfg . group ;
home = cfg . dataDir ;
createHome = false ;
uid = config . ids . uids . ipfs ;
description = " I P F S d a e m o n u s e r " ;
2020-05-15 21:57:56 +00:00
packages = [
2022-10-06 18:32:54 +00:00
pkgs . kubo-migrator
2020-05-15 21:57:56 +00:00
] ;
2020-04-24 23:36:52 +00:00
} ;
} ;
users . groups = mkIf ( cfg . group == " i p f s " ) {
ipfs . gid = config . ids . gids . ipfs ;
} ;
systemd . tmpfiles . rules = [
" d ' ${ cfg . dataDir } ' - ${ cfg . user } ${ cfg . group } - - "
] ++ optionals cfg . autoMount [
" d ' ${ cfg . ipfsMountDir } ' - ${ cfg . user } ${ cfg . group } - - "
" d ' ${ cfg . ipnsMountDir } ' - ${ cfg . user } ${ cfg . group } - - "
] ;
2022-03-30 09:31:56 +00:00
# The hardened systemd unit breaks the fuse-mount function according to documentation in the unit file itself
systemd . packages = if cfg . autoMount
then [ cfg . package . systemd_unit ]
else [ cfg . package . systemd_unit_hardened ] ;
2020-06-18 07:06:33 +00:00
2021-04-25 03:57:28 +00:00
systemd . services . ipfs = {
path = [ " / r u n / w r a p p e r s " cfg . package ] ;
2020-06-18 07:06:33 +00:00
environment . IPFS_PATH = cfg . dataDir ;
2021-04-25 03:57:28 +00:00
preStart = ''
2021-09-18 10:52:07 +00:00
if [ [ ! - f " $ I P F S _ P A T H / c o n f i g " ] ] ; then
ipfs init $ { optionalString cfg . emptyRepo " - e " } - - profile = $ { profile }
2020-04-24 23:36:52 +00:00
else
2021-09-18 10:52:07 +00:00
# After an unclean shutdown this file may exist which will cause the config command to attempt to talk to the daemon. This will hang forever if systemd is holding our sockets open.
rm - vf " $ I P F S _ P A T H / a p i "
2022-04-27 09:35:20 +00:00
'' + o p t i o n a l S t r i n g c f g . a u t o M i g r a t e ''
2022-10-06 18:32:54 +00:00
$ { pkgs . kubo-migrator } /bin/fs-repo-migrations - to ' $ { cfg . package . repoVersion } ' - y
2022-04-27 09:35:20 +00:00
'' + ''
2022-06-26 10:26:21 +00:00
ipfs - - offline config profile apply $ { profile } > /dev/null
2020-04-24 23:36:52 +00:00
fi
2021-04-25 03:57:28 +00:00
'' + o p t i o n a l S t r i n g c f g . a u t o M o u n t ''
2021-07-03 03:11:41 +00:00
ipfs - - offline config Mounts . FuseAllowOther - - json true
ipfs - - offline config Mounts . IPFS $ { cfg . ipfsMountDir }
ipfs - - offline config Mounts . IPNS $ { cfg . ipnsMountDir }
2022-02-10 20:34:41 +00:00
'' + ''
ipfs - - offline config show \
| $ { pkgs . jq } /bin/jq ' . * $ extraConfig' - - argjson extraConfig $ {
2022-04-15 01:41:22 +00:00
escapeShellArg ( builtins . toJSON (
recursiveUpdate
{
Addresses . API = cfg . apiAddress ;
Addresses . Gateway = cfg . gatewayAddress ;
Addresses . Swarm = cfg . swarmAddress ;
}
cfg . extraConfig
) )
2022-02-10 20:34:41 +00:00
} \
| ipfs - - offline config replace -
'' ;
2020-06-18 07:06:33 +00:00
serviceConfig = {
2022-10-06 18:32:54 +00:00
ExecStart = [ " " " ${ cfg . package } / b i n / i p f s d a e m o n ${ kuboFlags } " ] ;
2020-06-18 07:06:33 +00:00
User = cfg . user ;
Group = cfg . group ;
2022-03-30 09:31:56 +00:00
StateDirectory = " " ;
2022-07-14 12:49:19 +00:00
ReadWritePaths = optionals ( ! cfg . autoMount ) [ " " cfg . dataDir ] ;
2020-06-18 07:06:33 +00:00
} // optionalAttrs ( cfg . serviceFdlimit != null ) { LimitNOFILE = cfg . serviceFdlimit ; } ;
} // optionalAttrs ( ! cfg . startWhenNeeded ) {
wantedBy = [ " d e f a u l t . t a r g e t " ] ;
2020-04-24 23:36:52 +00:00
} ;
2020-06-18 07:06:33 +00:00
systemd . sockets . ipfs-gateway = {
wantedBy = [ " s o c k e t s . t a r g e t " ] ;
2020-08-20 17:08:02 +00:00
socketConfig = {
2021-09-18 10:52:07 +00:00
ListenStream =
let
2020-08-20 17:08:02 +00:00
fromCfg = multiaddrToListenStream cfg . gatewayAddress ;
2021-09-18 10:52:07 +00:00
in
[ " " ] ++ lib . optional ( fromCfg != null ) fromCfg ;
ListenDatagram =
let
2020-08-20 17:08:02 +00:00
fromCfg = multiaddrToListenDatagram cfg . gatewayAddress ;
2021-09-18 10:52:07 +00:00
in
[ " " ] ++ lib . optional ( fromCfg != null ) fromCfg ;
2020-08-20 17:08:02 +00:00
} ;
2020-04-24 23:36:52 +00:00
} ;
2020-06-18 07:06:33 +00:00
systemd . sockets . ipfs-api = {
wantedBy = [ " s o c k e t s . t a r g e t " ] ;
2021-04-22 02:08:21 +00:00
# We also include "%t/ipfs.sock" because there is no way to put the "%t"
2020-06-15 15:56:04 +00:00
# in the multiaddr.
2021-09-18 10:52:07 +00:00
socketConfig . ListenStream =
let
2020-06-15 15:56:04 +00:00
fromCfg = multiaddrToListenStream cfg . apiAddress ;
2021-09-18 10:52:07 +00:00
in
[ " " " % t / i p f s . s o c k " ] ++ lib . optional ( fromCfg != null ) fromCfg ;
2020-04-24 23:36:52 +00:00
} ;
2022-04-27 09:35:20 +00:00
} ;
2020-04-24 23:36:52 +00:00
2022-04-27 09:35:20 +00:00
meta = {
maintainers = with lib . maintainers ; [ Luflosi ] ;
2020-04-24 23:36:52 +00:00
} ;
2022-10-06 18:32:54 +00:00
imports = [
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " e n a b l e " ] [ " s e r v i c e s " " k u b o " " e n a b l e " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " p a c k a g e " ] [ " s e r v i c e s " " k u b o " " p a c k a g e " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " u s e r " ] [ " s e r v i c e s " " k u b o " " u s e r " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " g r o u p " ] [ " s e r v i c e s " " k u b o " " g r o u p " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " d a t a D i r " ] [ " s e r v i c e s " " k u b o " " d a t a D i r " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " d e f a u l t M o d e " ] [ " s e r v i c e s " " k u b o " " d e f a u l t M o d e " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " a u t o M o u n t " ] [ " s e r v i c e s " " k u b o " " a u t o M o u n t " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " a u t o M i g r a t e " ] [ " s e r v i c e s " " k u b o " " a u t o M i g r a t e " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " i p f s M o u n t D i r " ] [ " s e r v i c e s " " k u b o " " i p f s M o u n t D i r " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " i p n s M o u n t D i r " ] [ " s e r v i c e s " " k u b o " " i p n s M o u n t D i r " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " g a t e w a y A d d r e s s " ] [ " s e r v i c e s " " k u b o " " g a t e w a y A d d r e s s " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " a p i A d d r e s s " ] [ " s e r v i c e s " " k u b o " " a p i A d d r e s s " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " s w a r m A d d r e s s " ] [ " s e r v i c e s " " k u b o " " s w a r m A d d r e s s " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " e n a b l e G C " ] [ " s e r v i c e s " " k u b o " " e n a b l e G C " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " e m p t y R e p o " ] [ " s e r v i c e s " " k u b o " " e m p t y R e p o " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " e x t r a C o n f i g " ] [ " s e r v i c e s " " k u b o " " e x t r a C o n f i g " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " e x t r a F l a g s " ] [ " s e r v i c e s " " k u b o " " e x t r a F l a g s " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " l o c a l D i s c o v e r y " ] [ " s e r v i c e s " " k u b o " " l o c a l D i s c o v e r y " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " s e r v i c e F d l i m i t " ] [ " s e r v i c e s " " k u b o " " s e r v i c e F d l i m i t " ] )
( mkRenamedOptionModule [ " s e r v i c e s " " i p f s " " s t a r t W h e n N e e d e d " ] [ " s e r v i c e s " " k u b o " " s t a r t W h e n N e e d e d " ] )
] ;
2020-04-24 23:36:52 +00:00
}