Skip to content

Commit

Permalink
nixos/reposilite: init module
Browse files Browse the repository at this point in the history
Co-authored-by: Jamalam <[email protected]>
  • Loading branch information
magneticflux- and Jamalam360 committed Dec 21, 2024
1 parent ecade5a commit 30f2a2d
Show file tree
Hide file tree
Showing 8 changed files with 379 additions and 0 deletions.
9 changes: 9 additions & 0 deletions nixos/doc/manual/redirects.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
{
"module-services-reposilite": [
"index.html#module-services-reposilite"
],
"module-services-reposilite-generating-a-token": [
"index.html#module-services-reposilite-generating-a-token"
],
"module-services-reposilite-quickstart": [
"index.html#module-services-reposilite-quickstart"
],
"book-nixos-manual": [
"index.html#book-nixos-manual"
],
Expand Down
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2411.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@

- [Rathole](https://github.com/rapiz1/rathole), a lightweight and high-performance reverse proxy for NAT traversal. Available as [services.rathole](#opt-services.rathole.enable).

- [Reposilite](https://reposilite.com), a lightweight and easy-to-use repository manager for Maven based artifacts in JVM ecosystem. Available as [services.reposilite](#opt-services.reposilite.enable).

- [Proton Mail bridge](https://proton.me/mail/bridge), a desktop application that runs in the background, encrypting and decrypting messages as they enter and leave your computer. Available as [services.protonmail-bridge](#opt-services.protonmail-bridge.enable).

- [chromadb](https://www.trychroma.com/), an open-source AI application database with batteries included. Available as [services.chromadb](options.html#opt-services.chromadb.enable).
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1539,6 +1539,7 @@
./services/web-apps/pretix.nix
./services/web-apps/privatebin.nix
./services/web-apps/prosody-filer.nix
./services/web-apps/reposilite.nix
./services/web-apps/rimgo.nix
./services/web-apps/rutorrent.nix
./services/web-apps/screego.nix
Expand Down
45 changes: 45 additions & 0 deletions nixos/modules/services/web-apps/reposilite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Reposilite {#module-services-reposilite}

Reposilite is a self-hosted repository manager for Maven based artifacts in JVM ecosystem.

Visit [the Reposilite project page](https://reposilite.com) to learn
more about it.

## Quickstart {#module-services-reposilite-quickstart}

Use the following configuration to start a public instance of Reposilite locally:

```nix
{
services.reposilite = {
enable = true;
settings = {
sslEnabled = true;
};
openFirewall = true;
};
}
```

## Generating a Token {#module-services-reposilite-generating-a-token}

You'll need to generate your first access token on the CLI (after which you can generate them in the web UI):

```
sudo systemctl stop reposilite.service
reposilite --working-directory /var/lib/reposilite --port 8084 --database "sqlite reposilite.db" --token <tokenName:tokenSecret>
```

If you have modified the `database` option, update the flag in the command above as such.

This creates a temporary token. With the server still running, access the web dashboard in a browser at `localhost:8084`, and create a permanent token by navigating to the `Console` tab and typing:

```
token-generate <name>
```

This will output a secret which you should save. You can then Ctrl-C to kill the Reposilite process and run the following command to restart the systemd service:

```
sudo systemctl start reposilite.service
```
293 changes: 293 additions & 0 deletions nixos/modules/services/web-apps/reposilite.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.reposilite;

inherit (lib)
mkEnableOption
mkPackageOption
mkOption
mkIf
mkDefault
getExe
types
;

# Reposilite actually uses https://github.com/dzikoysk/cdn, but its format is similar enough to YAMLs to use pkgs.formats.yaml.
settingsFormat = pkgs.formats.yaml { };
in
{
options.services.reposilite = {
enable = mkEnableOption "reposilite";
package = mkPackageOption pkgs "reposilite" { };

settings = mkOption {
type = types.submodule {
freeformType = settingsFormat.type;
options = {
hostname = mkOption {
description = ''
Hostname
The hostname can be used to limit which connections are accepted.
Use 0.0.0.0 to accept connections from anywhere.
127.0.0.1 will only allow connections from localhost.
'';
default = "0.0.0.0";
example = "127.0.0.1";
type = types.str;
};

port = mkOption {
description = "Port to bind";
default = 8080;
example = 5678;
type = types.port;
};

database = mkOption {
description = ''
Database configuration. Supported storage providers:
- mysql localhost:3306 database user password
- sqlite reposilite.db
- sqlite --temporary
Experimental providers (not covered with tests):
- postgresql localhost:5432 database user password
- h2 reposilite
'';
default = "sqlite reposilite.db";
example = "mysql localhost:3306 database user password";
type = types.str;
};

webThreadPool = mkOption {
description = ''
Max amount of threads used by core thread pool (min: 5)
The web thread pool handles first few steps of incoming http connections, as soon as possible all tasks are redirected to IO thread pool.
'';
default = 16;
example = 32;
type = types.int;
};

ioThreadPool = mkOption {
description = ''
IO thread pool handles all tasks that may benefit from non-blocking IO (min: 2)
Because most of tasks are redirected to IO thread pool, it might be a good idea to keep it at least equal to web thread pool.
'';
default = 8;
example = 12;
type = types.int;
};

databaseThreadPool = mkOption {
description = ''
Database thread pool manages open connections to database (min: 1)
Embedded databases such as SQLite or H2 don't support truly concurrent connections, so the value will be always 1 for them if selected.
'';
default = 1;
example = 3;
type = types.int;
};

compressionStrategy = mkOption {
description = ''
Select compression strategy used by this instance.
Using 'none' reduces usage of CPU & memory, but ends up with higher transfer usage.
GZIP is better option if you're not limiting resources that much to increase overall request times.
Available strategies: none, gzip
'';
default = "none";
example = "gzip";
type = types.enum [
"none"
"gzip"
];
};

idleTimeout = mkOption {
description = "Default idle timeout used by Jetty";
default = 30000;
example = 120000;
type = types.int;
};

bypassExternalCache = mkOption {
description = ''
Adds cache bypass headers to each request from /api/* scope served by this instance.
Helps to avoid various random issues caused by proxy provides (e.g. Cloudflare) and browsers.
'';
default = true;
type = types.bool;
};

cachedLogSize = mkOption {
description = "Amount of messages stored in cached logger.";
default = 32;
example = 64;
type = types.ints.unsigned;
};

defaultFrontend = mkOption {
description = "Enable default frontend with dashboard.";
default = true;
type = types.bool;
};

basePath = mkOption {
description = ''
Set custom base path for Reposilite instance.
It's not recommended to mount Reposilite under custom base path and you should always prioritize subdomain over this option.
'';
default = "/";
example = "/maven";
type = types.str;
};

debugEnabled = mkOption {
description = "Debug mode";
default = false;
type = types.bool;
};

};
};
description = "Configuration written to the config file for Reposilite.";
default = { };
};

openFirewall = mkOption {
description = ''
Whether to open the firewall for Reposilite.
This adds `services.reposilite.settings.port` to `networking.firewall.allowedTCPPorts`.
'';
default = false;
type = types.bool;
};

nginx = mkOption {
type = types.submodule {
options = {
enable = mkEnableOption "the nginx reverse proxy virtual host";

hostname = mkOption {
description = ''
The hostname for the nginx virtual host.
'';
example = "reposilite.example.com";
type = types.str;
};
};
};

description = "nginx config TODO";
default = { };
};

user = mkOption {
type = types.nonEmptyStr;
default = "reposilite";
description = "User account under which Reposilite runs.";
};

group = mkOption {
type = types.nonEmptyStr;
default = "reposilite";
description = "Group account under which Reposilite runs.";
};
};

config = mkIf cfg.enable (
let
config-cdn = settingsFormat.generate "reposilite.cdn" cfg.settings;
in
{
users = {
users."${cfg.user}" = {
description = "Reposilite user";
group = cfg.group;
isSystemUser = true;
};
groups."${cfg.group}" = { };
};

# This is done so that the reposilite command is available in PATH so users can setup their first token (see reposilite.md).
environment.systemPackages = [ cfg.package ];

systemd.services.reposilite = {
description = "Reposilite server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];

serviceConfig = {
Type = "exec";
User = cfg.user;
Group = cfg.group;
UMask = "0077";
ExecStart = "${getExe cfg.package} --local-configuration ${config-cdn} --local-configuration-mode none --working-directory /var/lib/reposilite";
WorkingDirectory = "/var/lib/reposilite";
StateDirectory = "reposilite";

ProtectProc = "invisible";
ProcSubset = "pid";
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = true;
PrivateIPC = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;

RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
LockPersonality = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RemoveIPC = true;

CapabilityBoundingSet = [ "" ];

NoNewPrivileges = true;
SystemCallFilter = [ "@system-service" ];
SystemCallErrorNumber = "EPERM";
SystemCallArchitectures = "native";

DevicePolicy = "closed";

IPAddressDeny = "any";
IPAddressAllow = cfg.settings.hostname;
};
};

services.reposilite = mkIf cfg.nginx.enable {
settings.hostname = mkDefault "localhost";
openFirewall = mkDefault false;
};

networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.server.port ];

services.nginx = mkIf cfg.nginx.enable {
enable = true;
virtualHosts.${cfg.nginx.hostname} = {
locations."/" = {
proxyPass = "http://${cfg.settings.hostname}:${toString cfg.settings.port}/";
};
};
};
}
);

meta.doc = ./reposilite.md;
meta.maintainers = [ lib.maintainers.jamalam ];
}
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,7 @@ in {
redmine = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./redmine.nix {};
renovate = handleTest ./renovate.nix {};
replace-dependencies = handleTest ./replace-dependencies {};
reposilite = runTest ./reposilite.nix;
restartByActivationScript = handleTest ./restart-by-activation-script.nix {};
restic-rest-server = handleTest ./restic-rest-server.nix {};
restic = handleTest ./restic.nix {};
Expand Down
Loading

0 comments on commit 30f2a2d

Please sign in to comment.