This commit is contained in:
muon 2024-12-16 15:47:21 +00:00
parent 614caf7d6f
commit 15a3ca5e14
6 changed files with 410 additions and 0 deletions

View file

@ -27,6 +27,8 @@ in {
mods.server.videos.enable = true;
mods.server.reddit.enable = true;
mods.server.grav.enable = true;
mods.tailscale.enable = true;
mods.wireguard.id = 3;

View file

@ -3,6 +3,7 @@
./containers
./gaming
./docker
./grav
./media.nix
./sync.nix

View file

@ -0,0 +1,36 @@
diff -Nurp grav-src/system/src/Grav/Common/Cache.php grav-src-nixos/system/src/Grav/Common/Cache.php
--- grav-src/system/src/Grav/Common/Cache.php 1970-01-01 01:00:01.000000000 +0100
+++ grav-src-nixos/system/src/Grav/Common/Cache.php 2024-11-22 15:46:47.481175690 +0100
@@ -517,7 +517,7 @@ class Cache extends Getters
$output[] = '';
- if (($remove === 'all' || $remove === 'standard') && file_exists($user_config)) {
+ if (($remove === 'all' || $remove === 'standard') && file_exists($user_config) && is_writable($user_config)) {
touch($user_config);
$output[] = '<red>Touched: </red>' . $user_config;
@@ -544,7 +544,7 @@ class Cache extends Getters
{
$user_config = USER_DIR . 'config/system.yaml';
- if (file_exists($user_config)) {
+ if (file_exists($user_config) && is_writable($user_config)) {
touch($user_config);
}
diff -Nurp grav-src/system/src/Grav/Console/Gpm/SelfupgradeCommand.php grav-src-nixos/system/src/Grav/Console/Gpm/SelfupgradeCommand.php
--- grav-src/system/src/Grav/Console/Gpm/SelfupgradeCommand.php 1970-01-01 01:00:01.000000000 +0100
+++ grav-src-nixos/system/src/Grav/Console/Gpm/SelfupgradeCommand.php 2024-11-22 16:05:13.752536788 +0100
@@ -94,6 +94,11 @@ class SelfupgradeCommand extends GpmComm
$input = $this->getInput();
$io = $this->getIO();
+ # Adopted from Arch package.
+ $io->error('Grav cannot be upgraded this way as it has been installed with a distribution package.');
+ $io->writeln('Use Nix to upgrade.');
+ return 1;
+
if (!class_exists(ZipArchive::class)) {
$io->title('GPM Self Upgrade');
$io->error('php-zip extension needs to be enabled!');

View file

@ -0,0 +1,24 @@
{ pkgs, lib, config, ... }:
let cfg = config.mods.server;
in with lib; {
imports = [ ./service.nix ];
options.mods.server = {
grav = {
enable = mkEnableOption {
default = false;
description = "enables grav service";
};
};
};
config = {
services.grav = mkIf cfg.grav.enable {
enable = true;
systemSettings = {
log = { handler = "syslog"; };
pages = { theme = "agency"; };
};
};
};
}

View file

@ -0,0 +1,30 @@
{ pkgs, lib, fetchzip, ... }:
let version = "1.7.48";
in pkgs.stdenvNoCC.mkDerivation {
pname = "grav";
inherit version;
src = fetchzip {
url =
"https://github.com/getgrav/grav/releases/download/${version}/grav-admin-v${version}.zip";
hash = "sha256-e8WpdO0n3pY4Ajs1fvMkMI+CrR6uMitswvYS5rxal4g=";
};
patches = [ ./01-nix.patch ];
installPhase = ''
runHook preInstall
mkdir -p $out/
cp -R . $out/
runHook postInstall
'';
meta = with lib; {
description = "Fast, simple, and flexible, file-based web platform";
homepage = "https://getgrav.com";
maintainers = with maintainers; [ rycee ];
license = licenses.mit;
};
}

View file

@ -0,0 +1,317 @@
{ config, lib, pkgs, ... }:
let
inherit (lib)
generators mapAttrs mkDefault mkEnableOption mkIf mkPackageOption mkOption
types;
cfg = config.services.grav;
yamlFormat = pkgs.formats.yaml { };
poolName = "grav";
pkgs_grav = pkgs.callPackage ./package.nix { };
servedRoot = pkgs.runCommand "grav-served-root" { } ''
cp --reflink=auto --no-preserve=mode -r ${pkgs_grav} $out
for p in assets images user system/config; do
rm -rf $out/$p
ln -sf /var/lib/grav/$p $out/$p
done
'';
systemSettingsYaml =
yamlFormat.generate "grav-settings.yaml" cfg.systemSettings;
in {
options.services.grav = {
enable = mkEnableOption "grav";
root = mkOption {
type = types.path;
default = "/var/lib/grav";
description = ''
Root of the application.
'';
};
pool = mkOption {
type = types.str;
default = "${poolName}";
description = ''
Name of existing phpfpm pool that is used to run web-application.
If not specified a pool will be created automatically with
default values.
'';
};
virtualHost = mkOption {
type = types.nullOr types.str;
default = "grav";
description = ''
Name of the nginx virtualhost to use and setup. If null, do not setup
any virtualhost.
'';
};
phpPackage = mkPackageOption pkgs "php" { };
maxUploadSize = mkOption {
type = types.str;
default = "128M";
description = ''
The upload limit for files. This changes the relevant options in
{file}`php.ini` and nginx if enabled.
'';
};
systemSettings = mkOption {
type = yamlFormat.type;
default = { log = { handler = "syslog"; }; };
description = ''
Settings written to {file}`user/config/system.yaml`.
'';
};
};
config = mkIf cfg.enable {
services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
${poolName} = {
user = "grav";
group = "grav";
phpPackage = cfg.phpPackage.buildEnv {
extensions = { all, enabled }:
with all; [
apcu
ctype
curl
dom
filter
gd
mbstring
opcache
openssl
session
simplexml
xml
yaml
zip
];
extraConfig = generators.toKeyValue {
mkKeyValue = generators.mkKeyValueDefault { } " = ";
} {
output_buffering = "0";
short_open_tag = "Off";
expose_php = "Off";
error_reporting = "E_ALL";
display_errors = "stderr";
"opcache.interned_strings_buffer" = "8";
"opcache.max_accelerated_files" = "10000";
"opcache.memory_consumption" = "128";
"opcache.revalidate_freq" = "1";
"opcache.fast_shutdown" = "1";
"openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt";
catch_workers_output = "yes";
upload_max_filesize = cfg.maxUploadSize;
post_max_size = cfg.maxUploadSize;
memory_limit = cfg.maxUploadSize;
"apc.enable_cli" = "1";
};
};
phpEnv = {
GRAV_ROOT = toString servedRoot;
GRAV_SYSTEM_PATH = "${servedRoot}/system";
GRAV_CACHE_PATH = "/var/cache/grav";
GRAV_BACKUP_PATH = "/var/lib/grav/backup";
GRAV_LOG_PATH = "/var/log/grav";
GRAV_TMP_PATH = "/var/tmp/grav";
};
settings = mapAttrs (name: mkDefault) {
"listen.owner" = config.services.nginx.user;
"listen.group" = config.services.nginx.group;
"listen.mode" = "0600";
"pm" = "dynamic";
"pm.max_children" = 75;
"pm.start_servers" = 10;
"pm.min_spare_servers" = 5;
"pm.max_spare_servers" = 20;
"pm.max_requests" = 500;
"catch_workers_output" = 1;
};
};
};
services.nginx = mkIf (cfg.virtualHost != null) {
enable = true;
virtualHosts = {
${cfg.virtualHost} = {
root = "${servedRoot}";
locations = {
"= /robots.txt" = {
priority = 100;
extraConfig = ''
allow all;
access_log off;
'';
};
"~ \\.php$" = {
priority = 200;
extraConfig = ''
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${
config.services.phpfpm.pools.${cfg.pool}.socket
};
fastcgi_index index.php;
'';
};
"~* /(\\.git|cache|bin|logs|backup|tests)/.*$" = {
priority = 300;
extraConfig = ''
return 403;
'';
};
# deny running scripts inside core system folders
"~* /(system|vendor)/.*\\.(txt|xml|md|html|htm|shtml|shtm|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$" =
{
priority = 300;
extraConfig = ''
return 403;
'';
};
# deny running scripts inside user folder
"~* /user/.*\\.(txt|md|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$" =
{
priority = 300;
extraConfig = ''
return 403;
'';
};
# deny access to specific files in the root folder
"~ /(LICENSE\\.txt|composer\\.lock|composer\\.json|nginx\\.conf|web\\.config|htaccess\\.txt|\\.htaccess)" =
{
priority = 300;
extraConfig = ''
return 403;
'';
};
# deny all files and folder beginning with a dot (hidden files & folders)
"~ (^|/)\\." = {
priority = 300;
extraConfig = ''
return 403;
'';
};
"/" = {
priority = 400;
index = "index.php";
extraConfig = ''
try_files $uri $uri/ /index.php?$query_string;
'';
};
};
extraConfig = ''
index index.php index.html /index.php$request_uri;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag "noindex, nofollow";
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Frame-Options sameorigin;
add_header Referrer-Policy no-referrer;
client_max_body_size ${cfg.maxUploadSize};
fastcgi_buffers 64 4K;
fastcgi_hide_header X-Powered-By;
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
'';
};
};
};
systemd.tmpfiles.rules = let datadir = "/var/lib/grav";
in map (dir: "d '${dir}' 0750 grav grav - -") [
"/var/cache/grav"
"${datadir}/assets"
"${datadir}/backup"
"${datadir}/images"
"${datadir}/system/config"
"${datadir}/user/accounts"
"${datadir}/user/config"
"${datadir}/user/data"
"/var/log/grav"
];
# ++ [
# "L+ ${datadir}/user/config/system.yaml - - - - ${systemSettingsYaml}"
# ];
systemd.services = {
"phpfpm-${poolName}" = mkIf (cfg.pool == "${poolName}") {
# restartTriggers = [ servedRoot systemSettingsYaml ];
restartTriggers = [ servedRoot ];
serviceConfig = {
ExecStartPre = pkgs.writeShellScript "grav-pre-start" ''
function setPermits() {
chmod -R o-rx "$1"
chown -R grav:grav "$1"
}
tmpDir=/var/tmp/grav
dataDir=/var/lib/grav
mkdir $tmpDir
setPermits $tmpDir
for path in config/site.yaml pages plugins themes; do
fullPath="$dataDir/user/$path"
if [[ ! -e $fullPath ]]; then
cp --reflink=auto --no-preserve=mode -r \
${pkgs_grav}/user/$path $fullPath
fi
setPermits $fullPath
done
systemConfigDir=$dataDir/system/config
if [[ ! -e $systemConfigDir/system.yaml ]]; then
cp --reflink=auto --no-preserve=mode -r \
${pkgs_grav}/system/config/* $systemConfigDir/
fi
setPermits $systemConfigDir
'';
};
};
};
users.users.grav = {
isSystemUser = true;
description = "Grav service user";
home = "/var/lib/grav";
group = "grav";
};
users.groups.grav = { members = [ config.services.nginx.user ]; };
};
}