{"id":28469504,"url":"https://github.com/oldium/simple-repo-manager","last_synced_at":"2026-02-15T03:03:49.849Z","repository":{"id":296747499,"uuid":"994351274","full_name":"oldium/simple-repo-manager","owner":"oldium","description":"A simple repository manager for both Debian and RedHat repository formats","archived":false,"fork":false,"pushed_at":"2026-01-26T22:19:16.000Z","size":445,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-27T09:32:43.550Z","etag":null,"topics":["centos","curl","debian","dput","fedora","redhat","repository-manager","ubuntu","web"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oldium.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-01T18:50:33.000Z","updated_at":"2026-01-26T22:18:43.000Z","dependencies_parsed_at":"2025-06-02T05:09:43.880Z","dependency_job_id":"80e0a4e3-5f7a-4f54-a732-e458ba4a73ee","html_url":"https://github.com/oldium/simple-repo-manager","commit_stats":null,"previous_names":["oldium/simple-repo-manager"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/oldium/simple-repo-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oldium%2Fsimple-repo-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oldium%2Fsimple-repo-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oldium%2Fsimple-repo-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oldium%2Fsimple-repo-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oldium","download_url":"https://codeload.github.com/oldium/simple-repo-manager/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oldium%2Fsimple-repo-manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29466925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T01:01:38.065Z","status":"online","status_checked_at":"2026-02-15T02:00:07.449Z","response_time":118,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["centos","curl","debian","dput","fedora","redhat","repository-manager","ubuntu","web"],"created_at":"2025-06-07T09:00:42.000Z","updated_at":"2026-02-15T03:03:49.841Z","avatar_url":"https://github.com/oldium.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Simple Repository Manager\n\nThis is a [Node.js][nodejs] project providing a simple repository manager for\nDebian and RedHat repository formats. It has little logic, it is able to receive\nuploaded files by POST and PUT HTTP methods and uses third-party tools to\norganize the uploads into a repository structure.\n\nFeatures:\n\n* 🖥️ Web UI to browse the uploaded files.\n* ⌨️ Full support for keyboard and mouse navigation in the web UI.\n* 🧩 Customizable installation instructions shown on every page with built-in\n  Debian and RedHat templates.\n* 🌓 Dark mode is supported 😉.\n* 🚀 File upload by POST HTTP method.\n* 🚀 File upload by PUT HTTP method compatible with Debian's `dput` and\n  `dput-ng` tools.\n* ✒️ Supports building a signed repository.\n* 📦 Uses Debian's `reprepro` tool for repository management. Automatically\n  maintains the `reprepro` configuration.\n* 📦 Uses RedHat's `createrepo_c` tool for repository management.\n* ✂️ Separates distributions (Debian vs. Ubuntu) and for RedHat-like\n  repositories also releases (Fedora 41 vs. 42).\n* 🎨 Supports multiple distributions and releases.\n* 📂 Self-contained, serves the created repositories, a separate Nginx instance\n  is not necessary.\n\nThe project follows a minimal approach — upload the file and call the tool to do\nthe rest. If you need to do any change, do it manually in the repository and\ncall the tools to synchronize the repository metadata. Please be aware that\n`reprepro` configuration files are parsed and generated again every time, so\nmanual changes might be lost, see details [below](#repository-management-api).\n\n[nodejs]: https://nodejs.org\n\n## Quick Start\n\nThis project was developed and tested with [Node.js][nodejs] version 24 and a\npatched version of [npm][npm]. The project requires the following software to be\nfully operational (but starts without them as well):\n\n* 🎩 [createrepo_c][createrepo_c] version 1.2.0 or higher, older versions have\n  not been tested. Required for RedHat-like repositories.\n* 🎩🌀 [rnp][rnp] version 0.16.3 or higher, older versions have not been tested.\n  Optional, but required for signing repository metadata.\n* 🌀 [reprepro][reprepro] version 5.4.7 or higher, older versions do not support\n  `ddeb` files. Required for Debian-like repositories.\n* 🌀 [gpg][gpg] version 2.2.40 or higher, older versions have not been tested.\n  Optional, but required by `reprepro` tool for verifying signed Debian\n  packages.\n\n\u003e [!NOTE]\n\u003e All software packages are available in Debian Trixie, but unfortunately\n\u003e not the recent versions. Due to a [bug][reprepro-bug] in `reprepro` the latest\n\u003e version is 5.3.2, but that version does not support `ddeb` files. The\n\u003e Dockerfile contains a recipe to build and install `reprepro` package for\n\u003e Debian Trixie from sources taken from Debian Experimental release.\n\nTo install all Node.js development dependencies, run the following command:\n\n```bash\nnpm install\n```\n\nThe default configuration serves files from the local data directory `./data`,\nso you can run the server with the following command:\n\n```bash\nnpm run dev\n```\n\nThis will start the server listening on http://localhost:3000.\n\nThe Development Container (devcontainer in short) has all the dependencies\ninstalled, including `createrepo_c` and `reprepro`, so you can test the server\nwithout installing them on your local machine. Please consult the relevant\ndocumentation for your IDE, like [Visual Studio Code][vscode-devcontainer] or\n[JetBrains WebStorm][jetbrains-devcontainer], to learn how to run the\nDevelopment Containers.\n\nYou can also run the production version based on the `Dockerfile` with all the\nrequired software with Docker Compose:\n\n```bash\ndocker compose up --detach\n```\n\nThis will build the local Docker image (from `Dockerfile`) and start local\nserver listening at http://localhost (port 80 is forwarded to container port\n3000\\) with local folder `./data` mounted to `/app/data` in the container.\n\n[npm]: https://github.com/npm/cli/pull/8703#issuecomment-3452682658\n\n[createrepo_c]: https://github.com/rpm-software-management/createrepo_c\n\n[reprepro]: https://salsa.debian.org/debian/reprepro\n\n[rnp]: https://www.rnpgp.org/software/rnp/\n\n[gpg]: https://www.gnupg.org/\n\n[reprepro-bug]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1095493\n\n[vscode-devcontainer]: https://code.visualstudio.com/docs/devcontainers/containers\n\n[jetbrains-devcontainer]: https://www.jetbrains.com/help/webstorm/dev-containers-starting-page.html\n\n## Usage\n\nTo use the repository manager, you need to follow these steps:\n\n* Configure the server. See the [Configuration](#configuration) section below\n  for details.\n* Start the server. See the [Quick Start](#quick-start) section above for\n  details.\n* Upload the packages to the repository. See the\n  [Packages Upload API](#packages-upload-api) section below for details.\n* Build the repository. See the\n  [Repository Management API](#repository-management-api) section below for\n  details.\n* Use the repository in your distribution. See below for details on how to use\n  the repository in Debian-like and RedHat-like distributions.\n* Optionally, you can browse the repository using\n  the [Repository Browser](#repository-browser)\n\n### Debian-like Repository\n\nThe Debian-like repository is served at the following URI:\n\n```url\n\u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/deb/\u003cdistribution\u003e/\n```\n\nThe scheme depends on the configuration, it can be either `http` or `https`. For\nsigned repositories the GPG public key needs to be imported into the system\nkeyring. The public key is in the text form (“armored”) can be downloaded from\nthe following URI:\n\n```url\n\u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/deb/archive-keyring.asc\n```\n\nTo set up the signed repository on the Debian-based distribution, you can use\nthe following command:\n\n```bash\ncurl -fsSL \u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/deb/archive-keyring.asc | \n  sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/my-repo.gpg\n```\n\nThen add the repository to the APT sources list:\n\n```bash\nsudo tee /etc/apt/sources.list.d/my-repo.sources \u003e/dev/null \u003c\u003c'EOF'\nTypes: deb deb-src\nURIs: \u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/deb/\u003cdistribution\u003e/\nSuites: \u003crelease\u003e\nComponents: \u003ccomponent\u003e\nSigned-By: /etc/apt/trusted.gpg.d/my-repo.gpg\nEOF\n```\n\nIf you do not want to sign the repository, skip the `curl` command and omit the\n`Signed-By:` line in the source list command. The repository can be accessed\nwithout the GPG key, but it is not recommended for production use.\n\nNow you can update the APT package index and install the packages from the\nrepository:\n\n```bash\nsudo apt update\nsudo apt install \u003cpackage\u003e\n```\n\nThe real-life example after you uploaded the fictitious package `foo` for Debian\ndistribution's release Bookworm and `main` component would look like this:\n\n```bash\ncurl -fsSL https://my-repo.example.com/deb/archive-keyring.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/my-repo.gpg\n```\n\n```bash\nsudo tee /etc/apt/sources.list.d/my-repo.sources \u003e/dev/null \u003c\u003c'EOF'\nTypes: deb deb-src\nURIs: https://my-repo.example.com/deb/debian/\nSuites: bookworm\nComponents: main\nSigned-By: /etc/apt/trusted.gpg.d/my-repo.gpg\nEOF\n```\n\n```bash\nsudo apt update\nsudo apt install foo\n```\n\n### RedHat-like Repository\n\nThe RedHat-like repository is served at the following URI:\n\n```url\n\u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/rpm/\u003cdistribution\u003e/\u003crelease\u003e/\n```\n\nThe scheme depends on the configuration, it can be either `http` or `https`. For\nsigned repositories the GPG public key needs to be imported into the system\nkeyring. The public key is in the text form (“armored”) can be downloaded from\nthe following URI:\n\n```url\n\u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/rpm/RPM-GPG-KEY.asc\n```\n\nTo set up the signed repository on the RedHat-based distribution, you can use\nthe following command:\n\n```bash\nsudo curl -fsSL \u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/rpm/RPM-GPG-KEY.asc -o /etc/pki/rpm-gpg/RPM-GPG-KEY-my-repo\n```\n\nThen add the repository to the YUM/DNF configuration:\n\n```bash\nsudo tee /etc/yum.repos.d/my-repo.repo \u003e/dev/null \u003c\u003c'EOF'\n[rpm-my-repo]\nname=My Repository\nbaseurl=\u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/rpm/\u003cdistribution\u003e/\u003crelease\u003e/\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-my-repo\nEOF\n```\n\nAnd register the GPG public key with the YUM/DNF keyring and update the\nrepository metadata:\n\n```bash\nsudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-my-repo \u0026\u0026 \\\nsudo dnf -q makecache -y --disablerepo='*' --enablerepo=rpm-my-repo\n```\n\nThis configuration expects that the packages are either signed with the\nsignature available in the repository public GPG key, or the packages signature\nis already installed in the system keyring. If that is not the case and the\npackages signature should not be verified, you can omit the `gpgcheck=1`\nline.\n\nIf you do not have a signed repository at all, skip the `curl` command and omit\nthe `gpgcheck`, `repo_gpgcheck` and `gpgkey` lines in the repository\nconfiguration. The repository can be accessed without the GPG key, but it is not\nrecommended for production use.\n\nNow you can update the YUM/DNF package index and install the packages from the\nrepository:\n\n```bash\nsudo dnf check-update\nsudo dnf install \u003cpackage\u003e\n```\n\nThe real-life example after you uploaded the fictitious package `foo` for Fedora\nrelease 41 would look like this:\n\n```bash\nsudo curl -fsSL https://my-repo.example.com/rpm/RPM-GPG-KEY.asc -o /etc/pki/rpm-gpg/RPM-GPG-KEY-my-repo\n```\n\n```bash\nsudo tee /etc/yum.repos.d/my-repo.repo \u003e/dev/null \u003c\u003c'EOF'\n[rpm-my-repo]\nname=My Repository\nbaseurl=https://my-repo.example.com/rpm/fedora/41/\nenabled=1\ngpgcheck=1\ngpgpkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-my-repo\nEOF\n```\n\n```bash\nsudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-my-repo \u0026\u0026 \\\nsudo dnf -q makecache -y --disablerepo='*' --enablerepo=rpm-my-repo\n```\n\n```bash\nsudo dnf check-update\nsudo dnf install foo\n```\n\n## Repository Browser\n\nThe repository browser is a simple web interface to browse the uploaded files\nafter being transformed by the\n[Repository Management API](#repository-management-api) into the repositories.\nIt is available at the root `/` path of the server. The browser is not meant to\nbe a full-featured repository browser, it is just a simple interface to see what\nfiles are available in the repository and download them.\n\nThe browser is not protected by any authentication, so it is accessible to\nanyone who has access to the server.\n\nThe browser can be accessed at the following URI:\n\n```url\n\u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/\n```\n\nThe scheme depends on the configuration, it can be either `http` or `https`. For\nthe same example as in the [Usage](#usage) section, the browser could be\naccessed at:\n\n```url\nhttps://my-repo.example.com/\n```\n\n## Status API\n\nThe status API is available at the `/status` endpoint. It serves as a\nconfirmation that the server is up and running. The status response is a simple\ntext response with no particular structure containing the information that the\nserver is running.\n\n## Packages API\n\nThe packages API is designed to be used by tools like `dput`, `dput-ng` and\n`curl`. It can be optionally protected by basic authentication. See the\n[Configuration](#configuration) section for more details.\n\nThe packages API is versioned and the current path is `/api/v1`.\n\nThe response to all the packages API requests below the `/api` path is always\nJSON with the fields described below and additional fields described in the\nfollowing sections:\n\n* `message`: A human-readable message for the result of the operation.\n* `correlation`: Optional unique identifier with the `id` field, which can be\n  used to track the request in the server logs. Present only for HTTP response\n  error status codes `400` and higher.\n\n### Packages Status API\n\nThe status API is available at the `/api/v1/status` endpoint. It serves as a\nconfirmation that the authentication is correctly set up because the same rules\napply as for the other upload APIs. The status response contains the following\nfields:\n\n* `message`: A message that the server is up and running.\n* `api`: Dictionary with the following structure:\n  * `deb`:\n    * `enabled`: A boolean indicating that the Debian-like Upload API is\n      correctly configured and enabled.\n  * `rpm`:\n    * `enabled`: A boolean indicating that the RedHat-like Upload API is\n      correctly configured and enabled.\n\n## Packages Upload API\n\nThe packages API is designed to be used by tools like `dput`, `dput-ng` and\n`curl`. It can be optionally protected by basic authentication. See the\n[Configuration](#configuration) section for more details.\n\nThe packages upload API is prefixed with `/api/v1/upload`.\n\nThe response to all the Upload API requests below the `/api/v1/upload` path is\nalways JSON with the following fields:\n\n* `message`: A human-readable message describing the result of the upload.\n* `files`: Optional array of uploaded files. Each entry contains the following\n  fields:\n  * `filename`: The name of the uploaded file.\n  * `status`: The upload status, which can be `\"ok\"` or `\"failed\"`.\n  * `path`: Optional path of the uploaded file without the `/api/v1/upload`\n    prefix.\n* `correlation`: Optional unique identifier with the `id` field, which can be\n  used to track the request in the server logs. Present only for HTTP response\n  error status codes `400` and higher.\n\n### Debian Packages Upload API\n\n\u003e [!NOTE]\n\u003e The Debian Upload API is compatible with `dput` and `dput-ng` tools and can\n\u003e be used for uploading Debian-based distributions like Debian, Ubuntu, etc.\n\nThe Repository Management API (the `reprepro` tool) expects that all files have\nbeen uploaded already. This means that the client must upload the\n`\u003cpackage\u003e.changes` file and all files listed in the `\u003cpackage\u003e.changes` file.\nFor example, upload of the first packaged version of fictitious package `foo`\nversion `1.0` would require the following files (the full list of files varies\nbased on the source package and distribution):\n\n* `foo_1.0-1_amd64.changes`\n* `foo_1.0-1_amd64.dsc`\n* `foo_1.0-1_amd64.deb`\n* `foo-dbgsym_1.0-1_amd64.deb` or `foo-dbgsym_1.0-1_amd64.ddeb`\n* `foo_1.0-1_amd64.buildinfo`\n* `foo_1.0.orig.tar.gz`\n* `foo_1.0-1.debian.tar.xz`\n\nThe `buildinfo` file is required only because it is part of the `changes` file,\nbut it will not be stored within the repository. All other files (built package,\nsource package, debug symbols) are stored in the repository.\n\n\u003e [!IMPORTANT]\n\u003e The `\u003cdistribution\u003e` component in the URIs must match the `Distribution:` tag\n\u003e of the `\u003cpackage\u003e.changes` file.\n\n#### POST API\n\n* `/api/v1/upload/deb/\u003cdistribution\u003e/\u003crelease\u003e/\u003ccomponent\u003e`\n* `/api/v1/upload/deb/\u003cdistribution\u003e/\u003crelease\u003e/\u003ccomponent\u003e/\u003csub-component\u003e`\n\nThe POST API expects a `multipart/form-data` request with the field `package`\n(can be changed, see [Configuration](#configuration) section) containing the\nuploaded files. In case of multiple files in the same request, the field name\nmust be `package` without any additional brackets. The `curl` tool can be used\nto upload the files with the following command:\n\n```bash\ncurl -u \"\u003cusername\u003e:\u003cpassword\u003e\" \\\n  -F \"package=@foo_1.0-1_amd64.changes\" \\\n  -F \"package=@foo_1.0-1_amd64.dsc\" \\\n  -F \"package=@foo_1.0-1_amd64.deb\" \\\n  -F \"package=@foo-dbgsym_1.0-1_amd64.deb\" \\\n  -F \"package=@foo_1.0-1_amd64.buildinfo\" \\\n  -F \"package=@foo_1.0.orig.tar.gz\" \\\n  -F \"package=@foo_1.0-1.debian.tar.xz\" \\\n  https://\u003chost\u003e:\u003cport\u003e/api/v1/upload/deb/\u003cdistribution\u003e/\u003crelease\u003e/\u003ccomponent\u003e\n```\n\nFor example, to upload the package to Debian Bookworm distribution into\ncomponent `main`, the URI would look like:\n\n```url\nhttps://my-repo.example.com/api/v1/upload/deb/debian/bookworm/main`\n```\n\nTo upload the file to the Debian Bookworm security update distribution and\ncomponent `updates/main`, one could use:\n\n```url\nhttps://my-repo.example.com/api/v1/upload/deb/debian/bookworm-security/updates/main`\n```\n\nFor **testing** with plain HTTP and disabled authorization one could use\n`http` instead of `https` and omit the `-u` argument with the username and\npassword:\n\n```bash\ncurl -F \"package=@foo_1.0-1_amd64.changes\" \\\n  -F \"package=@foo_1.0-1_amd64.dsc\" \\\n  -F \"package=@foo_1.0-1_amd64.deb\" \\\n  -F \"package=@foo-dbgsym_1.0-1_amd64.deb\" \\\n  -F \"package=@foo_1.0-1_amd64.buildinfo\" \\\n  -F \"package=@foo_1.0.orig.tar.gz\" \\\n  -F \"package=@foo_1.0-1.debian.tar.xz\" \\\n  http://\u003chost\u003e:\u003cport\u003e/api/v1/upload/deb/\u003cdistribution\u003e/\u003crelease\u003e/\u003ccomponent\u003e\n```\n\n#### PUT API\n\n* `/api/v1/upload/deb/\u003cdistribution\u003e/\u003crelease\u003e/\u003ccomponent\u003e/\u003cfile\u003e`\n* `/api/v1/upload/deb/\u003cdistribution\u003e/\u003crelease\u003e/\u003ccomponent\u003e/\u003csub-component\u003e/\u003cfile\u003e`\n\nThe PUT API is meant to be used by `dput` and `dput-ng` tools. The example\n`.dput.cf` corresponding to the section above for Debian Bookworm distribution\nand `main` component could look like:\n\n```ini\n[bookworm-main]\nfqdn=\u003cusername\u003e:\u003cpassword\u003e@my-repo.example.com:443\nincoming=/api/v1/upload/deb/debian/bookworm/main\nmethod=https\ndistributions=bookworm\n```\n\nand call the `dput` tool with the following command:\n\n```bash\ndput bookworm-main foo_1.0-1_amd64.changes\n```\n\nOr in case of the Debian Bookworm security update distribution and component\n`updates/main` one could use:\n\n```ini\n[bookworm-security-main]\nfqdn=\u003cusername\u003e:\u003cpassword\u003e@my-repo.example.com:443\nincoming=/api/v1/upload/deb/debian/bookworm-security/updates/main\nmethod=https\ndistributions=bookworm-security\n```\n\nand call the `dput` tool with the following command:\n\n```bash\ndput bookworm-security-main foo_1.0-1_amd64.changes\n```\n\nFor **testing** with plain HTTP and disabled authorization one could use\n`method=http` and omit the username and password from the `fqdn` parameter:\n\n```ini\n[bookworm-main-test]\nfqdn=my-repo.example.com:80\nincoming=/api/v1/upload/deb/debian/bookworm/main\nmethod=http\ndistributions=bookworm\n```\n\n### RedHat-like Packages Upload API\n\nThe Repository Management API (the `createrepo_c` tool) is not so strict like in\nthe Debian-like repository case, so it works even for single RPMs. For the\nfictitious package `foo` version `1.0` the following files could be uploaded to\nhave both the source and binary RPMs:\n\n* `foo-1.0-1.x86_64.rpm`\n* `foo-1.0-1.x86_64.src.rpm`\n\n#### POST API\n\n* `/api/v1/upload/rpm/\u003cdistribution\u003e/\u003crelease\u003e`\n\nThe POST API expects a `multipart/form-data` request with the field `package`\n(can be changed, see [Configuration](#configuration) section) containing the\nuploaded files. In case of multiple files in the same request, the field name\nmust be `package` without any additional brackets. The `curl` tool can be used\nto upload the files with the following command:\n\n```bash\ncurl -u \"\u003cusername\u003e:\u003cpassword\u003e\" \\\n  -F \"package=@foo-1.0-1.x86_64.rpm\" \\\n  -F \"package=@foo-1.0-1.x86_64.src.rpm\" \\\n  https://\u003chost\u003e:\u003cport\u003e/api/v1/upload/rpm/\u003cdistribution\u003e/\u003crelease\u003e\n```\n\nFor example, to upload the package to Fedora release 41, the URI would look\nlike:\n\n```url\nhttps://my-repo.example.com/api/v1/upload/rpm/fedora/41`\n```\n\nFor **testing** with plain HTTP and disabled authorization one could use\n`http` instead of `https` and omit the `-u` argument with the username and\npassword:\n\n```bash\ncurl -F \"package=@foo-1.0-1.x86_64.rpm\" \\\n  -F \"package=@foo-1.0-1.x86_64.src.rpm\" \\\n  http://\u003chost\u003e:\u003cport\u003e/api/v1/upload/rpm/\u003cdistribution\u003e/\u003crelease\u003e\n```\n\n#### PUT API\n\n* `/api/v1/upload/rpm/\u003cdistribution\u003e/\u003crelease\u003e/\u003cfile\u003e`\n\nThe PUT API accepts single file uploads. The `curl` tool can be used to upload\nthe file:\n\n```bash\ncurl -u \"\u003cusername\u003e:\u003cpassword\u003e\" \\\n  -T \"foo-1.0-1.x86_64.rpm\" \\\n  https://\u003chost\u003e:\u003cport\u003e/api/v1/upload/rpm/\u003cdistribution\u003e/\u003crelease\u003e/foo-1.0-1.x86_64.rpm\n```\n\nFor example, to upload the package to Fedora release 41, the URI would look\nlike:\n\n```url\nhttps://my-repo.example.com/api/v1/upload/rpm/fedora/41/foo-1.0-1.x86_64.rpm\n```\n\nIf the URI ends with a slash `/`, the file name is appended by `curl`\nautomatically:\n\n```bash\ncurl -u \"\u003cusername\u003e:\u003cpassword\u003e\" \\\n  -T \"foo-1.0-1.x86_64.rpm\" \\\n  https://\u003chost\u003e:\u003cport\u003e/api/v1/upload/rpm/\u003cdistribution\u003e/\u003crelease\u003e/\n```\n\nSo in the same example as above, one would use:\n\n```url\nhttps://my-repo.example.com/api/v1/upload/rpm/fedora/41/\n```\n\nIt is also possible to upload multiple files in multiple requests with a single\ncommand:\n\n```bash\ncurl -u \"\u003cusername\u003e:\u003cpassword\u003e\" \\\n  -T \"{foo-1.0-1.x86_64.rpm,foo-1.0-1.x86_64.src.rpm}\" \\\n  https://\u003chost\u003e:\u003cport\u003e/api/v1/upload/rpm/\u003cdistribution\u003e/\u003crelease\u003e/\n```\n\nFor **testing** with plain HTTP and disabled authorization one could use\n`http` instead of `https` and omit the `-u` argument with the username and\npassword:\n\n```bash\ncurl -T \"foo-1.0-1.x86_64.rpm\" \\\n  http://\u003chost\u003e:\u003cport\u003e/api/v1/upload/rpm/\u003cdistribution\u003e/\u003crelease\u003e/\n```\n\n### Repository Management API\n\nTo build the repository from the uploaded files, send the `POST` request to the\n`/api/v1/repo/import` endpoint. There is nothing read from the request body, so\nit might be empty.\n\nThe repository build can be triggered by issuing the following `curl` command:\n\n```bash\ncurl -u \"\u003cusername\u003e:\u003cpassword\u003e\" \\\n  -X POST https://\u003chost\u003e:\u003cport\u003e/api/v1/repo/import\n```\n\nFor **testing** with plain HTTP and disabled authorization one could use `http`\ninstead of `https` and omit the `-u` argument with the username and password:\n\n```bash\ncurl -X POST http://\u003chost\u003e:\u003cport\u003e/api/v1/repo/import\n```\n\nThe repository build prepares the configuration for the tools and calls the\n`reprepro` and `createrepo_c` binaries to build the actual repositories.\nCurrently, the request is synchronous, so the response will come when the tools\nfinish their work. You can continue using the other APIs, even the file upload\nAPI, while the repository build is in progress. The file upload API might be\ndelayed slightly, though, because the first step of the repository build is to\nmove the uploaded files to the processing directory for the tools to pick them\nup. During this move operation, the upload API requests are delayed.\n\n## Configuration\n\nThe configuration is stored entirely in the environment variables. The\ndescription and default values of the environment variables are listed in the\nfile [`env.example`][env-example]. You can use this file as a template for your\nown configuration and load it into the environment by one of the methods\nmentioned in the following sections.\n\nPlease also check the [Quick Start](#quick-start) section for the list of\nrequired tools.\n\n### Docker Configuration\n\nFor Docker, make a copy of the [`env.example`][env-example] to `.env` file\n(choose your name) and pass the path to the `docker run` command with\n`--env-file .env` option:\n\n```bash\ndocker run --detach \\\n  --name simple-repo-manager \\\n  --publish 80:3000 \\\n  --env-file .env \\\n  --volume ./data:/app/data \\\n  simple-repo-manager\n```\n\nAlternatively, you can set the environment variables directly in the\n`--env VARIABLE=value` option, or use the value from the current environment by\npassing the shorter `--env VARIABLE` form:\n\n```bash\ndocker run --detach \\\n  --name simple-repo-manager \\\n  --publish 80:3000 \\\n  --env UPLOAD_FIELD_NAME=file \\\n  --volume ./data:/app/data \\\n  simple-repo-manager\n```\n\n\u003e [!NOTE]\n\u003e When configuring HTTPS server (see\n\u003e [Configuration Examples](#configuration-examples)), replace the exposed port\n\u003e number 80 by port 443 in the `ports` element. Alternative to running HTTPS\n\u003e server is using an SSL-terminating reverse proxy.\n\n### Docker Compose Configuration\n\nFor Docker Compose, copy the [`env.example`][env-example] file to `.env` in the\nsame directory as the `compose.yml` file. The Docker Compose will load it\nautomatically. You can also use the `env_file` element in the `compose.yml` file\nto specify the path to the `.env` file (and choose a different file name), or\nuse the `environment` element to set the environment variables directly. It is\nalso possible to set the environment variables by overriding the `env_file`\nand/or `environment` elements in the `compose.override.yml` file, which is\nloaded automatically by Docker Compose.\n\nFor the simple `compose.yml` file:\n\n```yaml\nservices:\n  simple-repo-manager:\n    image: simple-repo-manager\n    init: true\n    volumes:\n      - \"./data:/app/data\"\n    ports:\n      - \"127.0.0.1:80:3000\"\n      - \"[::1]:80:3000\"\n```\n\nyou can override the environment variables in the `.env` file:\n\n```dotenv\nUPLOAD_FIELD_NAME=file\n```\n\nor directly in the `compose.yml` file, or in the `compose.override.yml` file as\nin the following example:\n\n```yaml\nservices:\n  simple-repo-manager:\n    environment:\n      UPLOAD_FIELD_NAME: file\n```\n\n\u003e [!NOTE]\n\u003e When configuring HTTPS server (see\n\u003e [Configuration Examples](#configuration-examples)), replace the exposed port\n\u003e number 80 by port 443 in the `ports` element. Alternative to running HTTPS\n\u003e server is using an SSL-terminating reverse proxy.\n\n### Local Development Configuration\n\nFor local development, the most convenient way is to benefit from the\n[`dotenv`][dotenv] package, which is already a dependency of the project. You\ncan use it by creating a file named `.env` in the root of the project directory\nwith the content of [`env.example`][env-example] file and then start the\napplication.\n\nTo change the environment file path, you can specify the path in the\n`DOTENV_CONFIG_PATH` environment variable. To prevent loading `.env` file\nentirely, you can set the `DOTENV_CONFIG_PATH` environment variable to\n`/dev/null`.\n\n[env-example]: https://github.com/oldium/simple-repo-manager/blob/master/env.example\n\n[dotenv]: https://www.npmjs.com/package/dotenv\n\n### Configuration Examples\n\nPlease consult the [`env.example`][env-example] file for the full list of\nenvironment variables. The following examples show how to configure the\napplication using the environment variables for specific use cases.\n\nHTTPS server running on port 443 (default HTTPS port) with certificates located\nin the current directory in `certs/key.pem` and `certs/cert.pem` files:\n\n```dotenv\nHTTP_PORT=443\nHTTPS_KEY_FILE=certs/key.pem\nHTTPS_CERT_FILE=certs/cert.pem\n```\n\nUpload API limited to only local accesses going through the reverse proxy\nrunning on server 10.1.2.1 and filling `X-Forwarded-For` header:\n\n```dotenv\nTRUST_PROXY=10.1.2.1\nUPLOAD_ALLOWED_IPS=loopback,10.1.2.0/24\n```\n\nUpload API protected by basic authentication with username `rico` and password\n`kaboom`, and username `kowalski` and password `candy-canes`:\n\n```dotenv\nUPLOAD_BASIC_AUTH=rico:kaboom, kowalski:candy-canes\n```\n\nUse different field for POST uploads, e.g. `file`:\n\n```dotenv\nUPLOAD_FIELD_NAME=file\n```\n\nUse different directories for data, e.g. `/data/incoming`, `/data/repo` and\n`/data/repo-state`:\n\n```dotenv\nINCOMING_DIR=/data/incoming\nREPO_DIR=/data/repo\nREPO_STATE_DIR=/data/repo-state\n```\n\nUse GPG private key `repo-key.asc` (ASCII-armored format or binary format,\nextension does not matter) located in the current directory for signing the\nrepository metadata:\n\n```dotenv\nGPG_PRIVATE_KEY_FILE=repo-key.asc\n```\n\nUse GPG public keys stored in the `gpg-keyring.asc` file and `gpg-public-keys`\ndirectory for checking the uploaded packages by the `reprepro` tool for\nDebian-like repositories:\n\n```dotenv\nGPG_PUBLIC_KEYS_FILE=gpg-keyring.asc\nGPG_PUBLIC_KEYS_DIR=gpg-public-keys\n```\n\nDefine `Origin:` and `Description:` tags separately for the Debian and Ubuntu\ndistributions metadata:\n\n```dotenv\nDEB_ORIGIN_DEBIAN=My Debian Repository\nDEB_DESCRIPTION_DEBIAN=My Debian Repository for Debian distributions\nDEB_ORIGIN_UBUNTU=My Ubuntu Repository\nDEB_DESCRIPTION_UBUNTU=My Ubuntu Repository for Ubuntu distributions\n```\n\nRun the Docker container with UID `1001` and GID `1001`:\n\n```dotenv\nUID=1001\nGID=1001\n```\n\n### Installation Instructions HTML Templates\n\nThe installation instructions are shown on every page and are rendered by HTML\ntemplate engine [η (eta)][eta-sources], please consult the eta\n[documentation][eta-documentation] for more details on the templating engine.\nAlso, please check [`env.example`][env-example] file for the description of\n`TEMPLATES_DIR` environment variable for the possibility to define custom\ntemplates, the details on available template variables and how to override them.\n\n\u003e [!NOTE]\n\u003e The templates are cached, so to test changes, you need to restart the\n\u003e application.\n\nBrief overview of the templating engine functions:\n\n* `\u003c%` `%\u003e` - execute JavaScript block\n* `\u003c%=` `%\u003e` - evaluate JavaScript expression and escape the result for\n  inclusion in HTML\n* `\u003c%~` `%\u003e` - evaluate JavaScript expression and output it verbatim\n\nThe opening and closing tags can contain white-space stripping flags:\n\n* `\u003c%-` - strip one leading newline\n* `\u003c%_` - strip all leading whitespaces\n* `-%\u003e` - strip one trailing newline\n* `_%\u003e` - strip all trailing whitespaces\n\nThe opening tags can be combined with the function, like `\u003c%- =` (space is\noptional) to evaluate JavaScript expression.\n\nInclusion of other templates:\n\n* `\u003c%~ include('template') %\u003e` - include another template by name\n  (defined environment variable `TEMPLATES_DIR` is required for this\n  functionality)\n* `\u003c%~ include('@default-deb') %\u003e` - include built-in Debian installation\n  instructions template\n* `\u003c%~ include('@default-rpm') %\u003e` - include built-in RedHat installation\n  instructions template\n* `\u003c%~ include('@default-rpm', {repoName: \"My RPM Repository\"}) %\u003e` - evaluate\n  built-in RedHat repository installation instructions template, but override\n  the `repoName` value\n\nFor particular usage of the templating tags please consult the default templates\nin the [`templates`][templates] source code directory.\n\nExample of the template for the installation instructions for OpenSUSE and SUSE\nLinux Enterprise Server (SLES) distributions with upload `\u003cdistribution\u003e` name\nused as simply `suse` could be:\n\n*`templates/rpm-suse.eta.html`*:\n\n```html\n\u003c% if (gpgUri) { -%\u003e\n\u003cpre\u003esudo mkdir -p \u003c%= gpgKeyDir %\u003e \u0026\u0026 \\\nsudo curl -fsSL \u003c%= gpgUri %\u003e -o \u003c%= gpgKeyDir %\u003e/\u003c%= gpgKeyFile %\u003e\u003c/pre\u003e\n\u003c% } -%\u003e\n\u003cpre\u003esudo tee /etc/zypp/repos.d/\u003c%= repoDashSlug %\u003e.repo \u003e/dev/null \u003c\u003c'EOF'\n[\u003c%= repoDashSlug %\u003e]\nname=\u003c%= repoName %\u003e\nbaseurl=\u003c%= releaseUri %\u003e\nenabled=1\nautorefresh=1\n\u003c% if (gpgUri) { -%\u003e\ngpgcheck=1\npkg_gpgcheck=1\ngpgkey=file://\u003c%= gpgKeyDir %\u003e/\u003c%= gpgKeyFile %\u003e\n\u003c% } -%\u003e\nEOF\n\u003c/pre\u003e\n\u003cpre\u003esudo rpm --import \u003c%= gpgKeyDir %\u003e/\u003c%= gpgKeyFile %\u003e \u0026\u0026 \\\nsudo zypper refresh \u003c%= repoDashSlug %\u003e\n\u003c/pre\u003e\n```\n\nTo activate the template for all SUSE distributions, you need to set the\n`TEMPLATES_DIR` environment variable to the directory containing the template\nfile:\n\n```dotenv\nRPM_DISTRO_NAME_SUSE=SUSE\nTEMPLATES_DIR=templates\n```\n\nThe `RPM_DISTO_NAME_SUSE` environment variable is set to make the name shown on\nthe web UI as SUSE instead of the default capitalized Suse.\n\nWhen using Docker, propagate the `templates` directory to the container:\n\n* Docker: Add `--volume ./templates:/app/templates` command-line argument.\n* Docker Compose: Add the following to the service definition or the override\n  definition:\n\n  ```yaml\n  services:\n    simple-repo-manager:\n      volumes:\n        - \"./templates:/app/templates\"\n  ```\n\nAnd, as a last step, restart the application to apply the new configuration.\n\n[eta-sources]: https://github.com/bgub/eta\n\n[eta-documentation]: https://eta.js.org/\n\n[templates]: https://github.com/oldium/simple-repo-manager/tree/master/templates\n\n### Signing Repository Metadata\n\nThe repository metadata can be signed using GPG. The signing is done by the\n`reprepro` tool for Debian-like repositories and by `rnp` tool for RedHat-like\nrepositories. The signing key is not generated and needs to be provided by the\nadministrator. The best practice is to use the same GPG private key used for\nsigning the packages, so the repository metadata is signed with the same key as\nthe packages themselves. The private key can be provided in the\n`GPG_PRIVATE_KEY_FILE` environment variable, which can point to either an\nASCII-armored file (usually with `.asc` extension) or a binary file (usually  \nwith `.gpg` extension).\n\n\u003e [!IMPORTANT]\n\u003e Please note that the Repository Management API does not sign the uploaded\n\u003e packages; it only signs the metadata. The uploader must sign the packages\n\u003e themselves before uploading them to the repository.\n\nThe public key is extracted automatically during server start-up from the\nprivate key and is _added_ as an ASCII-armored key to the repository files\n`\u003cREPO_DIR\u003e/deb/archive-keyring.asc` and `\u003cREPO_DIR\u003e/rpm/RPM-GPG-KEY.asc`, which\ncorrespond to the following URIs:\n\n```url\n\u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/deb/archive-keyring.asc\n\u003cscheme\u003e://\u003chost\u003e:\u003cport\u003e/rpm/RPM-GPG-KEY.asc\n```\n\nIf the public key file already exists, it is parsed, and if the public key is\nnot found there, the new public key is added to the top of the file. The public\nkeys are not merged, so they can be found easily. Nothing is ever removed from\nthe file, so if some public keys need to be removed, that must be done manually.\n\n\u003e [!IMPORTANT]\n\u003e Any manual changes to the repository public key files need to preserve the\n\u003e ASCII-armored format.\n\nIf the packages are signed with a different key not available in the system\nkeyring, the corresponding public key can either be manually added to the\nrepository keyring files or supplied to the user differently. For example, by\nproviding a native package with the public keys and signed with the repository\nprivate key.\n\nThe Debian-like repository metadata is signed by the `reprepro` tool and results\nin the following files in the repository:\n\n* `Release` file containing the metadata for the repository.\n* `Release.gpg` file containing the GPG signature of the `Release` file.\n* `InRelease` file containing the metadata for the repository in ASCII-armored\n  format and signed by the GPG key.\n\nThe RedHat-like repository metadata is signed by the `rnp` tool and results in\nthe following files in the repository:\n\n* `repodata/repomd.xml` file containing the metadata for the repository.\n* `repodata/repomd.xml.asc` file containing the GPG signature of the\n  `repodata/repomd.xml` file.\n\n### Package Signatures\n\nThe repository manager does not sign the uploaded packages, it only signs the\nrepository metadata. The uploader must sign the packages themselves.\n\n## Production Build\n\nThe recommended way to run the Simple Repository Manager in production is to use\nDocker. The project provides a `Dockerfile` file to build the Docker image,\nincluding all required tools (see [Quick Start](#quick-start) for the list of\ntools). See below for details on how to build and run the Docker image.\n\n### Manual Build\n\nTo build the production version of the application, run:\n\n```bash\nnpm run build\n```\n\nThis will create a production build in the `dist` directory. The application can\nthen be started with:\n\n```bash\nnpm run prod\n```\n\nThis `dist` directory is not self-contained, it needs `node_modules` in order to\nrun, and `scripts` to handle the RedHat-like repositories and signing. So to\ncreate the smallest runnable application, you need to copy the `dist` and\n`scripts` directories, as well as the `package.json` and `package-lock.json`\nfiles to the target directory (the example uses `/app` directory, use any target\ndirectory you like) and prepare the `node_modules` directory with the following\ncommands:\n\n```bash\nmkdir -p /app/dist\ncp --recursive scripts/ dist/ package.json package-lock.json /app/\ncd /app\nnpm ci --omit=dev\n```\n\nThe resulting target directory now contains the production build of the\napplication, which can be run with:\n\n```bash\ncd /app\nNODE_ENV=production \\\n  node --enable-source-maps ./dist/server.js\n```\n\n\u003e [!NOTE]\n\u003e The `--enable-source-maps` option is used to enable source maps for debugging\n\u003e the production build. It is not required, but it is recommended for easier\n\u003e finding the location of the code in the source files.\n\nThe configuration (see [Configuration](#configuration) section for details) can\nbe supplied by environment variables set in the `.env` file located in the\ntarget directory. It will be automatically loaded by the application when it\nstarts. Alternatively, you can set the environment variables directly in the\nenvironment before starting the application.\n\nTo prevent loading `.env` file in the production, you can set the\n`DOTENV_CONFIG_PATH` environment variable to `/dev/null` or any non-existing\nfile.\n\nPlease also check the [Quick Start](#quick-start) section for the list of\nrequired tools.\n\n### Docker Build\n\nTo build the Docker image, run the following command in the root of the project\ndirectory:\n\n```bash\ndocker build -t simple-repo-manager .\n```\n\nThis will create a Docker image with the name `simple-repo-manager`. The\n`Dockerfile` contains all the necessary tools, including `createrepo_c`,\n`reprepro`, `rnp` and `gpg`, so the image is self-contained and can be used to\nrun the application in production.\n\n\u003e [!NOTE]\n\u003e The author of Simple Repo Manager creates the release builds with the\n\u003e following command, which ensures that fresh third-party images are used and\n\u003e adds additional metadata to the Docker image itself:\n\u003e\n\u003e ```bash\n\u003e docker buildx build --progress=plain --attest type=provenance,mode=max \\\n\u003e   --attest type=sbom,generator=docker/scout-sbom-indexer:latest \\\n\u003e   --no-cache -f .\\Dockerfile . -t simple-repo-manager\n\u003e ```\n\nThe Docker image exposes the port `3000` and by default expected the data\ndirectory to be mounted to `/app/data` in the container. The data directory\ncontains the repository data, so it needs to be persistent. To run the Docker\nimage on port 80 and use local directory `data` for persistent repository\nstorage, you can use the following command:\n\n```bash\ndocker run --detach \\\n  --name simple-repo-manager \\\n  --publish 80:3000 \\\n  --volume ./data:/app/data \\\n  simple-repo-manager\n```\n\nThe Docker container uses user `node` with UID `1000` and GID `1000` by default\nto run the application. The entrypoint script `entrypoint.sh` is initially\nstarted as user `root` and fixes the ownership of the `INCOMING_DIR`,\n`REPO_DIR`, `REPO_STATE_DIR` and optionally `GPGHOMEDIR` directories recursively\nduring startup. The numerical user and group IDs can be changed by setting the\n`UID` and `GID` environment variables passed to the started container like in\nthe following command:\n\n```bash\ndocker run --detach \\\n  --name simple-repo-manager \\\n  --publish 80:3000 \\\n  --volume ./data:/app/data \\\n  --env UID=1001 --env GID=1001 \\\n  simple-repo-manager\n```\n\nSee the [Configuration](#configuration) section for details on how to configure\nthe Docker environment.\n\n### Docker Compose\n\nFeel free to use the provided `compose.yml` file as a basis to run the Docker\nimage with Docker Compose on production. The file contains the same\nconfiguration as the `docker run` command above, but it is more convenient to\nuse. You can start the Docker container with the following command:\n\n```bash\ndocker compose up --detach\n```\n\nThe provided `compose.yml` compiles the Docker image from the sources. You will\nprobably want to replace the `build` element by specifying the particular image\nname, e.g. `image: simple-repo-manager`, with the name of the pre-built Docker\nimage for use in production.\n\nSee the [Configuration](#configuration) section for details on how to configure\nthe Docker Compose environment.\n\n## Troubleshooting\n\n### Repository Management API Call Failed\n\nIf you encounter any issues with the repository management tools, consult the\nserver logs for the executed commands and execute the commands manually to see\nthe output and debug the issue.\n\nIf you run the application in Docker, you can view the logs with the following\ncommand:\n\n```bash\ndocker logs simple-repo-manager\n```\n\nor in the case of the Docker Compose:\n\n```bash\ndocker compose logs simple-repo-manager\n```\n\nYou can then enter the Docker container and run the commands manually to\ntroubleshoot the issue with the following command:\n\n```bash\ndocker exec -u node -it simple-repo-manager /bin/bash\n```\n\nor in the case of the Docker Compose:\n\n```bash\ndocker compose exec -u node simple-repo-manager /bin/bash\n```\n\nThen you can execute the commands from the logs to see the output and debug the\nissue.\n\n\u003e [!CAUTION]\n\u003e Please be aware that the Debian-like repository management tools reuse\n\u003e some state files (`…/conf/incoming` and `…/conf/override`), so you can\n\u003e reliably troubleshoot only the _last_ `reprepro` `processincoming` call\n\u003e (successful or failed). If the last operation was successful, run the\n\u003e Repository Management API endpoint again until the last operation fails.\n\nIf you have the persistent storage mounted as a host directory into the\ncontainer, you can benefit from using the local editor instead of editing the\nfiles in the container directly.\n\nPlease note the argument `-u node`, which starts `/bin/bash` inside the\ncontainer as user `node`. The default is user `root`, so if you omit the\n`-u node` argument, you will enter the container as the `root` user.\n\n\u003e [!IMPORTANT]\n\u003e If you omit the `-u node` option and enter the container as the `root`\n\u003e user, some files inside the `INCOMING_DIR`, `REPO_DIR` or `REPO_STATE_DIR`\n\u003e might not be fully accessible by the `node` user. The entrypoint script\n\u003e [`entrypoint.sh`][entrypoint] will fix the ownership of these files on the\n\u003e next container restart, so if you used the user `root` to test anything\n\u003e inside the container, restart the container to fix the file permissions.\n\n[entrypoint]: https://github.com/oldium/simple-repo-manager/blob/master/entrypoint.sh\n\n### Reuploading Debian Packages with Changed Checksums\n\nIf you upload a Debian package with a different checksum than an existing\npackage, the `reprepro` tool rejects the files and reports an error similar to\nthis:\n\n```text\nFile \"pool/main/c/clevis/clevis_21-1+tpm1u8+deb12.dsc\" is already registered with different checksums!\n```\n\nIn that case you need to remove the existing package manually first. First, if\nyou are running the application in Docker, enter the container as described in\nthe [Repository Management API Call Failed](#repository-management-api-call-failed)\nsection.\n\nThen find-out which state directory you should be using, either check the logs,\nor `REPO_STATE_DIR` value from the environment (relative paths use `+b/`\nprefix). In the examples below, we assume that the environment value is unset\n(and uses a default value of `data/repo-state`) and that the distribution in\nquestion is `debian` and the release codename is `bookworm`. Our goal is to\nreupload all `clevis` packages with version `21-1+tpm1u8+deb12`:\n\n* List matching packages with Debian dependency-like filter in the repository:\n\n  ```bash\n  reprepro --confdir +b/data/repo-state/deb-debian/conf listfilter bookworm 'Package (% clevis*), $Version (= 21-1+tpm1u8+deb12)'\n  ```\n\n* Remove matching packages with a Debian dependency-like filter in the\n  repository:\n\n  ```bash\n  reprepro --confdir +b/data/repo-state/deb-debian/conf removefilter bookworm 'Package (% clevis*), $Version (= 21-1+tpm1u8+deb12)'\n  ```\n\nPlease check the Debian [manual page][man-reprepro] for details on how to use\nthe `reprepro` tool.\n\n[man-reprepro]: https://manpages.debian.org/experimental/reprepro/reprepro.1.en.html\n\n### Removing Packages from the Repository\n\nThe `reprepro` configuration is set to keep at most two (2) latest versions of\neach package in the repository. There is no such limit for the RedHat-like\nrepositories (there is no automatic cleanup in the `createrepo_c` tool).\n\nIf you need to remove the packages from the repository, it is currently a manual\nprocess. For Debian-like repository use the method mentioned above in the\n[Reuploading Debian Packages with Changed Checksums](#reuploading-debian-packages-with-changed-checksums)\nsection. For RedHat-like distributions, delete the respective files from the\nrepository directory and either regenerate the metadata as mentioned in the\n[Regenerate Metadata Signatures](#regenerate-metadata-signatures) section below.\n\n### Regenerate Metadata Signatures\n\nIf you have made any manual changes and need to regenerate the signatures, call\nthe [Repository Management API](#repository-management-api) endpoint to build\nthe repository metadata.\n\nThe Debian-like repository metadata signatures should be maintained by the\n`reprepro` tool already, because the signature script is automatically\nconfigured to run. So if you have made some manual changes and called the\n`reprepro` tool, the signatures should be up to date already.\n\nFor the RedHat-like repository metadata, the signature is generated by the\n`createrepo.sh` script, so either call the API mentioned above to call it for\nyou, or run the script manually (use your real directories and ensure that the\n`GPG_REPO_PRIVATE_KEY_FILE` environment variable is set correctly):\n\n```bash\ncd /app\nGPG_REPO_PRIVATE_KEY_FILE=/path/to/private-key.asc \\\n  ./scripts/createrepo.sh /app/data/repo/rpm/\u003cdistribution\u003e/\u003crelease\u003e ./scripts/sign.sh\n```\n\n## About the Project\n\n### Why?\n\nThere are some OpenSource alternatives like [OpenRepo][openrepo] or\n[Pulp][pulp]. However, the former one has not seen release since 2022 and for\nthe latter one you need to create multiple scripts to make it work\n(including patching the embedded Nginx configuration to run behind the\nSSL-terminating Nginx reverse proxy).\n\nSo I decided to create a simple repository manager, which does only the basics\n(package uploads, signing the repository metadata) and does not reinvent the\nwheel, so existing tools like `reprepro` and `createrepo_c` are used to manage\nthe repositories.\n\nWhen used with Docker, the project is self-contained, so it does not require any\nexternal Nginx reverse proxy but can run behind it as well.\n\n[openrepo]: https://github.com/openkilt/openrepo\n\n[pulp]: https://www.pulpproject.org/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foldium%2Fsimple-repo-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foldium%2Fsimple-repo-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foldium%2Fsimple-repo-manager/lists"}