Install privatebin, a pastebin alternative
diff --git a/flake.lock b/flake.lock
index 2bdf002..a7fb059 100644
--- a/flake.lock
+++ b/flake.lock
@@ -91,6 +91,22 @@
"type": "github"
}
},
+ "nixpkgs-privatebin": {
+ "locked": {
+ "lastModified": 1691328775,
+ "narHash": "sha256-nz7Myc/3sW7/tN1QDYKrmHnH5f5eGdbcFt1FRDstavk=",
+ "owner": "e1mo",
+ "repo": "nixpkgs",
+ "rev": "e1b0550bc7498d61ba95bcd089d62e256ef1677a",
+ "type": "github"
+ },
+ "original": {
+ "owner": "e1mo",
+ "ref": "privatebin",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
"nixpkgs-stable": {
"locked": {
"lastModified": 1685758009,
@@ -129,6 +145,7 @@
"flake-utils": "flake-utils",
"home-manager": "home-manager",
"nixpkgs": "nixpkgs_2",
+ "nixpkgs-privatebin": "nixpkgs-privatebin",
"scalpel": "scalpel",
"sops-nix": "sops-nix"
}
diff --git a/flake.nix b/flake.nix
index 8575fca..caa0571 100644
--- a/flake.nix
+++ b/flake.nix
@@ -15,12 +15,26 @@
inputs.scalpel.inputs.nixpkgs.follows = "nixpkgs";
inputs.scalpel.inputs.sops-nix.follows = "sops-nix";
- outputs = { self, nixpkgs, deploy-rs, home-manager, sops-nix, scalpel, ... }@inputs:
+ inputs.nixpkgs-privatebin.url = "github:e1mo/nixpkgs/privatebin";
+
+ outputs =
+ { self
+ , nixpkgs
+ , deploy-rs
+ , home-manager
+ , sops-nix
+ , scalpel
+ , nixpkgs-privatebin
+ , ...
+ }@inputs:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
+ overlays = [
+ (final: prev: { inherit (nixpkgs-privatebin.legacyPackages.${system}) privatebin pbcli; })
+ ];
};
in
rec {
@@ -51,6 +65,7 @@
./modules/mongodb.nix
./modules/node.nix
./modules/postgres.nix
+ ./modules/privatebin.nix
./modules/samba.nix
./modules/scalpel.nix
./modules/ssh.nix
@@ -59,6 +74,7 @@
./modules/tesseract.nix
./modules/vaultwarden.nix
sops-nix.nixosModules.sops
+ "${nixpkgs-privatebin}/nixos/modules/services/web-apps/privatebin.nix"
{
users.mutableUsers = false;
}
diff --git a/modules/caddy/caddyfile.nix b/modules/caddy/caddyfile.nix
index f3c8b20..69fbe2b 100644
--- a/modules/caddy/caddyfile.nix
+++ b/modules/caddy/caddyfile.nix
@@ -18,6 +18,80 @@
match = [{ host = hosts; }];
terminal = true;
};
+ PHPRoute = hosts: root: socket: {
+ handle = [
+ {
+ handler = "subroute";
+ routes = [
+ {
+ handle = [
+ {
+ handler = "vars";
+ inherit root;
+ }
+ ];
+ }
+ {
+ handle = [
+ {
+ handler = "static_response";
+ headers.Location = [ "{http.request.orig_uri.path}/" ];
+ status_code = 307;
+ }
+ ];
+ match = [
+ {
+ file.try_files = [ "{http.request.uri.path}/index.php" ];
+ not = [ { path = ["*/"]; } ];
+ }
+ ];
+ }
+ {
+ handle = [
+ {
+ handler = "rewrite";
+ uri = "{http.matchers.file.relative}";
+ }
+ ];
+ match = [
+ {
+ file = {
+ split_path = [ ".php" ];
+ try_files = [
+ "{http.request.uri.path}"
+ "{http.request.uri.path}/index.php"
+ "index.php"
+ ];
+ };
+ }
+ ];
+ }
+ {
+ handle = [
+ {
+ handler = "reverse_proxy";
+ transport = {
+ protocol = "fastcgi";
+ split_path = [".php"];
+ };
+ upstreams = [{ dial = socket; }];
+ }
+ ];
+ match = [{ path = ["*.php"]; }];
+ }
+ {
+ handle = [
+ {
+ handler = "file_server";
+ }
+ ];
+ }
+ ];
+ }
+ ];
+ match = [{ host = hosts; }];
+ terminal = true;
+ };
HTTPRedirectRoute = hosts: goto: {
handle = [
{
@@ -286,6 +360,11 @@
"syncthing.thecoded.prof"
"syncthing.hopescaramels.com"
] [ "localhost:8384" ])
+ (PHPRoute
+ [ "paste.clicks.codes" "paste.coded.codes" ]
+ "${pkgs.privatebin}/share/privatebin"
+ "unix/${config.services.phpfpm.pools.privatebin.socket}"
+ )
];
};
srv1 = {
diff --git a/modules/postgres.nix b/modules/postgres.nix
index 8f6c5f1..7a5074a 100644
--- a/modules/postgres.nix
+++ b/modules/postgres.nix
@@ -12,6 +12,7 @@
ensureDatabases = [
"vaultwarden"
+ "privatebin"
];
ensureUsers = [
@@ -34,6 +35,12 @@
"DATABASE vaultwarden" = "ALL PRIVILEGES";
};
}
+ {
+ name = "privatebin";
+ ensurePermissions = {
+ "DATABASE privatebin" = "ALL PRIVILEGES";
+ };
+ }
] ++ (map
(name: (
{
@@ -66,6 +73,7 @@
(lib.mkAfter (lib.pipe [
{ user = "clicks_grafana"; passwordFile = config.sops.secrets.clicks_grafana_db_password.path; }
{ user = "vaultwarden"; passwordFile = config.sops.secrets.clicks_bitwarden_db_password.path; }
+ { user = "privatebin"; passwordFile = config.sops.secrets.clicks_privatebin_db_password.path; }
] [
(map (userData: ''
$PSQL -tAc "ALTER USER ${userData.user} PASSWORD '$(cat ${userData.passwordFile})';"
@@ -77,6 +85,7 @@
sops.secrets = lib.pipe [
"clicks_grafana_db_password"
"clicks_bitwarden_db_password"
+ "clicks_privatebin_db_password"
] [
(map (name: {
inherit name;
diff --git a/modules/privatebin.nix b/modules/privatebin.nix
new file mode 100644
index 0000000..5dd6a28
--- /dev/null
+++ b/modules/privatebin.nix
@@ -0,0 +1,73 @@
+{ config, lib, base, ... }:
+lib.recursiveUpdate
+{
+ services.nginx.enable = false; # PrivateBin attempts to enable nginx but we already use caddy
+ services.privatebin = {
+ enable = true;
+ settings = {
+ main = {
+ name = "Clicks Minute Paste";
+ basepath = "https://paste.clicks.codes/";
+ opendiscussion = true;
+ fileupload = true;
+
+ defaultformatter = "syntaxhighlighting";
+ syntaxhighlightingtheme = "sons-of-obsidian";
+ template = "bootstrap-dark";
+
+ info = ''Powered by <a href="https://privatebin.info/">PrivateBin</a>. Provided as a service free-of-charge by Clicks. Come chat with us <a href="https://matrix.to/#/#global:coded.codes"> on Matrix</a>'';
+ notice = "This service has no guarantee of uptime, and pastes are not backed up. If you need somewhere to host the last words of your wise old grandfather for time immemorial this is not the place.";
+
+ langaugeselection = true;
+ };
+
+ expire.default = "1month";
+
+ expire_options = {
+ "5min" = 300; # looks bonkers, but I'm trying to keep the list ordered while also keeping the privatebin label formatter happy
+ "10min" = 600;
+ "1hour" = 3600;
+ "1day" = 86400;
+ "1week" = 604800;
+ "1month" = 2592000;
+ };
+
+ formatter_options = {
+ syntaxhighlighting = "Source Code";
+ markdown = "Markdown";
+ plaintext = "Plain Text";
+ };
+
+ traffic = {
+ exempted = "10.0.0.0/8,127.0.0.0/8,169.254.0.0/16,172.16.0.0/12,192.168.0.0/16";
+ };
+
+ model.class = "Database";
+ model_options = {
+ dsn = "pgsql:host=localhost;dbname=privatebin";
+ tbl = "privatebin";
+ usr = "privatebin";
+ pwd._env = "PRIVATEBIN_DB_PASSWORD";
+ };
+ };
+ };
+}
+(
+ if base != null
+ then {
+ services.privatebin.environmentFiles = [
+ config.scalpel.trafos."privatebin.env".destination
+ ];
+
+ scalpel.trafos."privatebin.env" = {
+ source = builtins.toFile "privatebin.env" ''
+ PRIVATEBIN_DB_PASSWORD=!!privatebin_db_password!!
+ '';
+ matchers."privatebin_db_password".secret =
+ config.sops.secrets.clicks_privatebin_db_password.path;
+ owner = config.users.users.privatebin.name;
+ group = config.users.users.privatebin.group;
+ mode = "0400";
+ };
+ }
+ else {})
diff --git a/secrets/postgres.json b/secrets/postgres.json
index ae3bcfc..5bb202b 100644
--- a/secrets/postgres.json
+++ b/secrets/postgres.json
@@ -1,6 +1,7 @@
{
"clicks_grafana_db_password": "ENC[AES256_GCM,data:tFByC3OyhRLkDlfjwq3Kmc7PnTHWmkXpXuqOGb2AzA9dkAijPggPhgvCrbkY8/oL8QwQDaI24+XV3U/8A2UwLbzu0L5oaWV/E4EJbyvi8UKp8Wg8Au25E0nD5tJZm7QQ3FVERgoUefcB8AEPJ4Z8Rgx1PuoBeun9toT1GkJtmuYNNHpOcFrbmaI/Qf1MP+yFZLYjvB1jz07V04RGTv4jow61lWFknS2aPJyat43Ogp64lIkfjen7zCvj3CWghfJx87uxeXsnFHMrRwfONozUdw19Bq1uLUJ7xvPqDtr/1WKi1xvBe5ez7/PkPslNJlIToIlL89xN/lOm2iQR2BNeXg==,iv:ruC4PzKpWYsz2qe0KImUo0YhRt2cisYx306yfPtzi6c=,tag:U8vg7w1zyqXAWH3WzNAHFA==,type:str]",
"clicks_bitwarden_db_password": "ENC[AES256_GCM,data:Xr9h/QVazxn1tzSNJgPH9uk6RE2bk0fNyOVNxSlflQ14wnna0xA9Uw4CcN9DbPyvBCvYsKrxTJOAzLOn/K4rc/G1C7dPKpGADiTH5O+1wX+PifrDHtQyuqvaarwO3QA20ZW48A==,iv:yKYDF3X9fNO+rbnguo5DAiXfCkjH06VkpGBjB9NGv/s=,tag:W8fAVyJGh6jQxwHMN+RAPg==,type:str]",
+ "clicks_privatebin_db_password": "ENC[AES256_GCM,data:FqTQzRxzv1Jelr7uPgQO0g9n653ilAriacvfj0ZQ7mnD8PEpE5SsZ4z8pOZJxCyIHFGE1n1iFudTJ3RXdSdsQ3Rxw7/eoz7IlblnQFQQKdTbpApNAkKyCKr5tUhUPqjTFixxGwNO8yxNUCTtdrBBbVZoxyAwl8lWXhI78fiFGA8=,iv:lqCfX0P+xHtIJfRW1DUjfwNlmvRCkg+y+qogsETL0RM=,tag:H855oMdkflQP6Drlefv6dA==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
@@ -20,8 +21,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByN0hMaXF2S2xiTTNqbm9h\nSGNieGNjNThJTk0wZXNQejBXaW9MOEp2akNFCm8rWVc3WG9pVndERFZzUnFOZnVG\naFBxTENlQ0x0ZjdqUHF6SFBPKzQ4bUEKLS0tIGVJTmdveTZrNTRiSTl0cHRQeWhl\nY2RmUTVQVTNoMFhLdkc3WFZEcHAycnMKqr42TSx7Pqcu62XgX4gj/iq2tbkZjFxg\nOcWBsLzqOsu/r0w5cK2Ple6JFGIJwmT2SqVqZh1pPbPwYHHXHbEphg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
- "lastmodified": "2023-06-13T21:01:47Z",
- "mac": "ENC[AES256_GCM,data:vm4yvl63zP9abxXuCtjjRh9LOVq63Q3nc8o8p2wj+v0pd1ltVZAMKmi/c6f4q+s12M0EYNQbqspLpG4OYva6WinAIyVJIvjvBJGKseH+lB2GrO+3jwlanOiHRl2ueAhihfGgj3dgqGiLUKoT1jFewZMoAY+PiGhp+Bup/Ziky9g=,iv:4YGy2zExsKUGQ9WAir0MFH9mFirbCPkjS523w1wpys4=,tag:nF8pO9I57AGAydFupYYU0w==,type:str]",
+ "lastmodified": "2023-07-30T14:59:54Z",
+ "mac": "ENC[AES256_GCM,data:Miimq3cBEfHhtF+zUWzYUs0pGfEEvA0ZXJzgJabH19FfIMSR6dXpdN807i7Of1AGYNYlGpxS3aPbDrpB5wsKkDFwzTCIZDsaKeq0G/YVzNVxA7BVdw/I3048f/VqrGSenwPhbpElADrGsL+waXGbQ/GA5F4387yihi6ZenxeQIs=,iv:Tx4bRqLVaaNACumwumZrCPcfTg4i19TSpwd1Ifu1PmE=,tag:nFg7zNFiR9vah4bgId0jjA==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.7.3"