WIP: firefly-iii

This commit is contained in:
Patrick 2024-04-02 21:57:59 +02:00
parent 6c23fec8d9
commit a53ad9030d
Signed by: patrick
GPG key ID: 451F95EFB8BECD0F
16 changed files with 2227 additions and 36 deletions

View file

@ -23,6 +23,7 @@
oauth2-proxy = "oauth2";
netbird = "netbird";
actual = "actual";
firefly = "money";
};
in "${domains.${hostName}}.${config.secrets.secrets.global.domains.web}";
# TODO hard coded elisabeth nicht so schön
@ -152,7 +153,6 @@ in {
};
}
(blockOf "vaultwarden" {maxBodySize = "1G";})
(blockOf "actual" {})
(blockOf "forgejo" {maxBodySize = "1G";})
(blockOf "immich" {maxBodySize = "5G";})
(proxyProtect "adguardhome" {} true)
@ -160,6 +160,7 @@ in {
(blockOf "paperless" {maxBodySize = "5G";})
(proxyProtect "ttrss" {port = 80;} true)
(blockOf "yourspotify" {port = 80;})
(blockOf "firefly" {port = 80;})
(blockOf "apispotify" {
port = 3000;
upstream = "yourspotify";
@ -268,9 +269,9 @@ in {
// mkContainer "ollama" {}
// mkContainer "murmur" {}
// mkContainer "ttrss" {}
// mkContainer "firefly" {}
// mkContainer "yourspotify" {}
// mkContainer "netbird" {}
// mkContainer "actual" {}
// mkContainer "kanidm" {}
// mkContainer "nextcloud" {
enablePanzer = true;

View file

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILvc9EHXQzJUfl6QXcUbOYZk5d9PTWpp3weP9XjGaDMy

View file

@ -33,6 +33,7 @@
kanidm = uidGid 223;
oauth2_proxy = uidGid 224;
influxdb2 = uidGid 225;
firefly-iii = uidGid 226;
paperless = uidGid 315;
systemd-oom = uidGid 300;
systemd-coredump = uidGid 301;

176
modules/fireflyIII.nix Normal file
View file

@ -0,0 +1,176 @@
{
pkgs,
config,
lib,
...
}: let
cfg = config.services.firefly-iii;
inherit
(lib)
mkIf
types
mkEnableOption
mkOption
mkPackageOption
mapAttrs
mkDefault
;
package = cfg.package.override {
dataDir = cfg.dataDir;
};
in {
options.services.firefly-iii = {
enable = mkEnableOption "firefly-iii";
dataDir = mkOption {
description = "The firefly-iii data directory.";
default = "/var/lib/firefly-iii";
type = types.path;
};
package =
mkPackageOption pkgs "firefly-iii" {
};
phpPackage = mkPackageOption pkgs "php" {
example = "php82";
default = "php83";
};
database = mkOption {
description = "Which database to use";
default = "sqlite";
type = types.enum ["sqlite" "mysql" "pgsql"];
};
dbCreateLocally = mkOption {
type = types.bool;
default = false;
description = "Create the database locally.";
};
virtualHost = mkOption {
description = "The nginx virtualHost under which firefly-iii will be reachable";
type = types.str;
};
settings = mkOption {
type = with types; attrsOf (nullOr (oneOf [str path package]));
description = ''
The environment used by firefly-iii while running.
See [example](https://github.com/firefly-iii/firefly-iii/blob/main/.env.example) for value definitions.
'';
default = {
LOG_CHANNEL = "syslog";
};
example = {
ALLOW_WEBHOOKS = false;
};
};
};
config = mkIf cfg.enable {
services.firefly-iii.settings = {
DB_CONNECTION = cfg.database;
};
assertions = [
{
assertion = cfg.dbCreateLocally -> cfg.database == "sqlite";
message = "services.firefly-iii.dbCreateLocally is currently only supported for sqlite.";
}
];
services.phpfpm = {
pools.firefly-iii = {
phpOptions = ''
log_errors = on
'';
user = "firefly-iii";
group = "firefly-iii";
phpPackage = cfg.phpPackage;
phpEnv = cfg.settings;
settings = mapAttrs (_: mkDefault) {
"listen.mode" = "0660";
"listen.owner" = config.services.nginx.user;
"listen.group" = config.services.nginx.group;
"pm" = "dynamic";
"pm.max_children" = "32";
"pm.start_servers" = "2";
"pm.min_spare_servers" = "2";
"pm.max_spare_servers" = "4";
"pm.max_requests" = "500";
};
};
};
users.users.firefly-iii = {
group = "firefly-iii";
isSystemUser = true;
};
users.groups.firefly-iii.members = ["firefly-iii" config.services.nginx.user];
systemd.services.firefly-iii-setup = {
environment = cfg.settings;
description = "Preparation tasks for Firefly III";
before = ["phpfpm-firefly-iii.service"];
wantedBy = ["multi-user.target"];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
User = "firefly-iii";
WorkingDirectory = package;
};
script = ''
set -euo pipefail
umask 077
${lib.optionalString cfg.dbCreateLocally ''
mkdir -p ${cfg.dataDir}/storage/database/
touch ${cfg.dataDir}/storage/database/database.sqlite
''}
# migrate db
${lib.getExe cfg.phpPackage} artisan migrate --force
${lib.getExe cfg.phpPackage} artisan firefly-iii:upgrade-database
${lib.getExe cfg.phpPackage} artisan firefly-iii:correct-database
${lib.getExe cfg.phpPackage} artisan firefly-iii:report-integrity
${lib.getExe cfg.phpPackage} artisan firefly-iii:laravel-passport-keys
'';
};
# Data dir
systemd.tmpfiles.rules = [
"d ${cfg.dataDir} 0710 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/app 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/database 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/export 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/framework 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/framework/cache 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/framework/sessions 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/framework/views 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/logs 0700 firefly-iii firefly-iii - -"
"d ${cfg.dataDir}/storage/upload 0700 firefly-iii firefly-iii - -"
];
services.nginx = {
enable = mkDefault true;
recommendedSetup = true;
recommendedTlsSettings = mkDefault true;
recommendedOptimisation = mkDefault true;
recommendedGzipSettings = mkDefault true;
virtualHosts.${cfg.virtualHost} = {
root = "${package}/public";
locations = {
"/" = {
index = "index.php";
tryFiles = "$uri $uri/ /index.php?$query_string";
extraConfig = ''
autoindex on;
sendfile off;
'';
};
"~* \\.php(?:$|/)" = {
extraConfig = ''
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param modHeadersAvailable true; #Avoid sending the security headers twice
fastcgi_pass unix:${config.services.phpfpm.pools.firefly-iii.socket};
'';
};
};
};
};
};
}

View file

@ -0,0 +1,20 @@
{config, ...}: {
imports = [../fireflyIII.nix];
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [80];
};
services.firefly-iii = {
enable = true;
virtualHost = "money.${config.secrets.secrets.global.domains.web}";
settings = {
APP_URL = "https://money.${config.secrets.secrets.global.domains.web}";
TZ = "Europe/Berlin";
TRUSTED_PROXIES = "**";
SITE_OWNER = "firefly-admin@${config.secrets.secrets.global.domains.mail_public}";
APP_KEY = "ctiectiectiectctiectiectiectieie";
};
};
}

View file

@ -8,7 +8,7 @@
deploy = super.callPackage ./deploy.nix {};
netbird-dashboard = super.callPackage ./netbird-dashboard {};
minify = super.callPackage ./minify {};
firefly-iii = super.callPackage ./fireflyIII.nix {};
firefly-iii = super.callPackage ./firefly-iii {};
mongodb-bin = super.callPackage ./mongodb-bin.nix {};
awakened-poe-trade = super.callPackage ./awakened-poe-trade.nix {};
neovim-clean = super.neovim-unwrapped.overrideAttrs (_neovimFinal: neovimPrev: {

View file

@ -0,0 +1,19 @@
{
pkgs ?
import <nixpkgs> {
inherit system;
},
system ? builtins.currentSystem,
noDev ? false,
php ? pkgs.php,
phpPackages ? pkgs.phpPackages,
}: let
composerEnv = import ./composer-env.nix {
inherit (pkgs) stdenv lib writeTextFile fetchurl unzip;
inherit php phpPackages;
};
in
import ./php-packages.nix {
inherit composerEnv noDev;
inherit (pkgs) fetchurl fetchgit fetchhg fetchsvn;
}

View file

@ -0,0 +1,259 @@
# This file originates from composer2nix
{
stdenv,
lib,
writeTextFile,
fetchurl,
php,
unzip,
phpPackages,
}: let
inherit (phpPackages) composer;
filterSrc = src:
builtins.filterSource (path: type: type != "directory" || (baseNameOf path != ".git" && baseNameOf path != ".git" && baseNameOf path != ".svn")) src;
buildZipPackage = {
name,
src,
}:
stdenv.mkDerivation {
inherit name src;
nativeBuildInputs = [unzip];
buildCommand = ''
shopt -s dotglob
unzip $src
baseDir=$(find . -type d -mindepth 1 -maxdepth 1)
cd $baseDir
mkdir -p $out
mv * $out
'';
};
buildPackage = {
name,
src,
packages ? {},
devPackages ? {},
buildInputs ? [],
symlinkDependencies ? false,
executable ? false,
removeComposerArtifacts ? false,
postInstall ? "",
noDev ? false,
composerExtraArgs ? "",
unpackPhase ? "true",
buildPhase ? "true",
...
} @ args: let
reconstructInstalled = writeTextFile {
name = "reconstructinstalled.php";
executable = true;
text = ''
#! ${php}/bin/php
<?php
if(file_exists($argv[1]))
{
$composerLockStr = file_get_contents($argv[1]);
if($composerLockStr === false)
{
fwrite(STDERR, "Cannot open composer.lock contents\n");
exit(1);
}
else
{
$config = json_decode($composerLockStr, true);
if(array_key_exists("packages", $config))
$allPackages = $config["packages"];
else
$allPackages = array();
${lib.optionalString (!noDev) ''
if(array_key_exists("packages-dev", $config))
$allPackages = array_merge($allPackages, $config["packages-dev"]);
''}
$packagesStr = json_encode($allPackages, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
print($packagesStr);
}
}
else
print("[]");
?>
'';
};
constructBin = writeTextFile {
name = "constructbin.php";
executable = true;
text = ''
#! ${php}/bin/php
<?php
$composerJSONStr = file_get_contents($argv[1]);
if($composerJSONStr === false)
{
fwrite(STDERR, "Cannot open composer.json contents\n");
exit(1);
}
else
{
$config = json_decode($composerJSONStr, true);
if(array_key_exists("bin-dir", $config))
$binDir = $config["bin-dir"];
else
$binDir = "bin";
if(array_key_exists("bin", $config))
{
if(!file_exists("vendor/".$binDir))
mkdir("vendor/".$binDir);
foreach($config["bin"] as $bin)
symlink("../../".$bin, "vendor/".$binDir."/".basename($bin));
}
}
?>
'';
};
bundleDependencies = dependencies:
lib.concatMapStrings (dependencyName: let
dependency = dependencies.${dependencyName};
in ''
${
if dependency.targetDir == ""
then ''
vendorDir="$(dirname ${dependencyName})"
mkdir -p "$vendorDir"
${
if symlinkDependencies
then ''ln -s "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
else ''cp -av "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
}
''
else ''
namespaceDir="${dependencyName}/$(dirname "${dependency.targetDir}")"
mkdir -p "$namespaceDir"
${
if symlinkDependencies
then ''ln -s "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
else ''cp -av "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
}
''
}
'') (builtins.attrNames dependencies);
extraArgs = removeAttrs args ["packages" "devPackages" "buildInputs"];
in
stdenv.mkDerivation ({
buildInputs = [php composer] ++ buildInputs;
inherit unpackPhase buildPhase;
installPhase = ''
${
if executable
then ''
mkdir -p $out/share/php
cp -av $src $out/share/php/$name
chmod -R u+w $out/share/php/$name
cd $out/share/php/$name
''
else ''
cp -av $src $out
chmod -R u+w $out
cd $out
''
}
# Remove unwanted files
rm -f *.nix
export HOME=$TMPDIR
# Remove the provided vendor folder if it exists
rm -Rf vendor
# If there is no composer.lock file, compose a dummy file.
# Otherwise, composer attempts to download the package.json file from
# the registry which we do not want.
if [ ! -f composer.lock ]
then
cat > composer.lock <<EOF
{
"packages": []
}
EOF
fi
# Reconstruct the installed.json file from the lock file
mkdir -p vendor/composer
${php}/bin/php ${reconstructInstalled} composer.lock > vendor/composer/installed.json
# Copy or symlink the provided dependencies
cd vendor
${bundleDependencies packages}
${lib.optionalString (!noDev) (bundleDependencies devPackages)}
cd ..
# The post Install phase needs an APP_KEY
echo "APP_KEY=SomeRandomStringOf32CharsExactly" > .env
# Reconstruct autoload scripts
# We use the optimize feature because Nix packages cannot change after they have been built
# Using the dynamic loader for a Nix package is useless since there is nothing to dynamically reload.
composer dump-autoload --optimize ${lib.optionalString noDev "--no-dev"} ${composerExtraArgs}
# Run the install step as a validation to confirm that everything works out as expected
composer install --optimize-autoloader ${lib.optionalString noDev "--no-dev"} ${composerExtraArgs}
${lib.optionalString executable ''
# Reconstruct the bin/ folder if we deploy an executable project
${php}/bin/php ${constructBin} composer.json
ln -s $(pwd)/vendor/bin $out/bin
''}
${lib.optionalString (!symlinkDependencies) ''
# Patch the shebangs if possible
if [ -d $(pwd)/vendor/bin ]
then
# Look for all executables in bin/
for i in $(pwd)/vendor/bin/*
do
# Look for their location
realFile=$(readlink -f "$i")
# Restore write permissions
chmod u+wx "$(dirname "$realFile")"
chmod u+w "$realFile"
# Patch shebang
sed -e "s|#!/usr/bin/php|#!${php}/bin/php|" \
-e "s|#!/usr/bin/env php|#!${php}/bin/php|" \
"$realFile" > tmp
mv tmp "$realFile"
chmod u+x "$realFile"
done
fi
''}
if [ "$removeComposerArtifacts" = "1" ]
then
# Remove composer stuff
rm -f composer.json composer.lock
fi
# Execute post install hook
runHook postInstall
'';
}
// extraArgs);
in {
inherit filterSrc;
composer = lib.makeOverridable composer;
buildZipPackage = lib.makeOverridable buildZipPackage;
buildPackage = lib.makeOverridable buildPackage;
}

View file

@ -0,0 +1,47 @@
{
pkgs,
stdenv,
lib,
fetchFromGitHub,
dataDir ? "/var/lib/firefly-iii",
}: let
version = "6.1.13";
src = fetchFromGitHub {
owner = "firefly-iii";
repo = "firefly-iii";
rev = "v${version}";
hash = "sha256-85zI8uCyyoCflzxDkvba6FWa9B3kh179DJfQ2Um6MGM=";
};
package =
(import ./compose2nix.nix {
inherit pkgs;
inherit (stdenv.hostPlatform) system;
noDev = true;
php = pkgs.php83;
phpPackages = pkgs.php83Packages;
})
.overrideAttrs (oldAttrs: {
installPhase =
oldAttrs.installPhase
+ ''
rm -R $out/storage
ln -s ${dataDir}/storage $out/storage
ln -fs ${dataDir}/.env $out/.env
'';
});
in
package.override rec {
inherit src version;
pname = "firefly-iii";
meta = with lib; {
description = "Firefly III: a personal finances manager";
homepage = "https://github.com/firefly-iii/firefly-iii/";
changelog = "https://github.com/firefly-iii/firefly-iii/releases/tag/v${version}";
license = licenses.agpl3Only;
maintainers = with maintainers; [patrickdag];
mainProgram = "firefly-iii";
platforms = platforms.all;
};
}

File diff suppressed because it is too large Load diff

View file

@ -1,33 +0,0 @@
{
lib,
stdenv,
fetchFromGitHub,
}:
stdenv.mkDerivation rec {
pname = "firefly-iii";
version = "6.1.13";
src = fetchFromGitHub {
owner = "firefly-iii";
repo = "firefly-iii";
rev = "v${version}";
hash = "sha256-85zI8uCyyoCflzxDkvba6FWa9B3kh179DJfQ2Um6MGM=";
};
installPhase = ''
runHook preInstall
mkdir -p $out/
cp -R . $out/
runHook postInstall
'';
meta = with lib; {
description = "Firefly III: a personal finances manager";
homepage = "https://github.com/firefly-iii/firefly-iii/";
changelog = "https://github.com/firefly-iii/firefly-iii/releases/tag/v${version}";
license = licenses.agpl3Only;
maintainers = with maintainers; [patrickdag];
mainProgram = "firefly-iii";
platforms = platforms.all;
};
}

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
9xRD/oWYa5zpt7Om257Aj7U9IV6zKo4OqDBUxVzHo2A=

View file

@ -0,0 +1,15 @@
age-encryption.org/v1
-> X25519 xJo5HhKHIrFP7wbV//wpaFoboByUMZOXreZt5Xdd5BU
Ru6CBmrq1v/rbPhoPXYhCHq0yMGCCUiTgs6ZM5kVNKU
-> piv-p256 XTQkUA AivD+Matq7mjlIusMtx6+lHk5ryKZcg56EEwhGN71x2M
6qgJoPZWiuylup3zgJjYm1zLoG9YYL+as8UtGFhpnCg
-> piv-p256 ZFgiIw AqW0keuSK7y8oSO3JYe3/l+pAh+Wxqbu0XFNJ+qBH1Xc
vfCxAefSzfOo/1+ihhRS8Ilh7nsKwwyEf1LLRPfaKiQ
-> piv-p256 5vmPtQ Aqz7EelM5PCayYWA4IBPOjcPQp+qRU0TcTQIJM6cOBu9
t1bkON97ATB7CCcCFCOZVAr3PvZ0dFR9rnURWLD7dkk
-> piv-p256 ZFgiIw AvVb0aN4gHr586PdYixoAPBpF061efDQBshijna2MwQH
7TJos5wgP7QfSDLmjKvWEQCt1svv8/psA9os7FcG7Aw
-> mIBupI-grease jy yXj i/P I
M9tNIG4pdjXCQm9gWUWNr7bE0YBOzA
--- kKw6CxBObbcfeukkS/spDO+s4zcMkriNfDrfXoD04uw
 #¥sÏ®&ºJwÁ´Àüm~ÄÄS<C384>¼Ä&<04>X-Æ¥u—[WŒn¦tB[<01>죣ecÆHr×É)hÃg')Öð.M—Ыó U—Îkš