Adding a new app

Adding a new app

In order to proceed you should be familiar working with the Terminal and Git.

In this guide, we will explain how to add a new app to the Runtipi App Store. The process is pretty simple and should take you less than 20 minutes.


  • The app you want to add is free and open-source (or at least source available with a permissive license for personal use)
  • The app you want to add has an official and maintained docker image

Fork the repo

In order to open a pull request you need to fork the repo. Visit the official App Store repo (opens in a new tab) and start by clicking the "Fork" button in the upper right corner of the page. This will create a new repository with your name and an identical structure to the original repo.

Clone the repo locally

On your computer clone the repo you just forked.

git clone https://<your-github-username>/runtipi/runtipi-appstore

Create a new branch for your app

Navigate to the repoisitory you just cloned.

cd runtipi-appstore

Create a new branch for your app.

git checkout -b app/<app-name>

Create the app files

Each app requires at least the following files:

  • A docker-compose.yml file to run your app
  • A config.json file to configure your app
  • A description in markdown format
  • A logo in jpg format (512 x 512px)

Inside the repo open the apps folder and create a new folder for your app. The name should be the same as the app name without spaces or capital letters.

Create a new config.json file inside the newly create folder

  "name": "My super app",
  "available": true,
  "port": 8100,
  "exposable": true, # Wether the app can be exposed via a domain name
  "id": "my-app", # This should be the same name as the folder
  "description": "", # Long description of the app
  "tipi_version": 1, # Always 1 if you are adding a new app
  "version": "1.25.1", # The actual version of the app (not the tipi version)
  "categories": ["utilities"], # One or more categories for the app
  "short_desc": "", # Short description of the app
  "author": "", # Link or name of the author
  "source": "", # Link for git repo
  "website": "", # Link to the official website
  "form_fields": [] # Used to ask for more info to the user before installing. Will be explained further

Be sure to remove the comments from the example above an that the final content is a valid JSON format. You can easily check for validity in an online tool like JSONLint (opens in a new tab)

Available categories : utilities, network, media, development, automation, social, utilities, photography, security, featured, books, data, music, finance, ai

Details for all the options of the config.json file:

OptionDescriptionExample value
nameName of the appNextcloud
idThis should be the same name as the foldernextcloud
availableIf set to false, the app will not be available in the app storetrue
short_descShort description of the appNextcloud is a suite of client-server software for creating and using file hosting services.
authorLink or name of the original author of the app (opens in a new tab)
portPort used by the app. This port will be exposed to the host.8100
categoriesOne or more categories for the app["utilities", "network"]
descriptionLong description of the appNextcloud is a suite of client-server software for creating and using file hosting services. Nextcloud is free and open-source, which means that anyone is allowed to install and operate it on their own private server devices.
tipi_versionAlways 1 if you are adding a new app. Increment this number if you are updating an existing app1
versionThe actual version of the app (not the tipi version)1.25.1
sourceLink for git repo (opens in a new tab)
websiteLink to the official website (opens in a new tab)
exposableIf set to true, the app will allow the user to expose it via a domain name.true
force_exposeIf set to true, the app will require a domain name.true
generate_vapid_keysIf set to true, the app will generate VAPID keys for web push notifications. VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY will be available as environment variablestrue
url_suffixIf set, the app will be accessible at https://<your-domain>/<url_suffix>my-app
httpsIf set to true, the app will be accessible via https only.true
no_guiSet to true for apps with no GUI. Open button will be hiddentrue
supported_architecturesIf the app is only available for a specific architecture, you can specify it here. If not given, app will be available for all architectures["arm64", "amd64"]
uid, gidThese parameters allow you to give a specific set of permission for the app's data folder. Runtipi will automatically chown the data directory with the provided gid and uid. Both options need to be specified in order to apply1000

If you want to add a new category, please open a new issue.

When choosing a port, please make sure that it is not in use already. You can check (opens in a new tab) for an updated list. Feel free to let us know if there are any missing ones!

In the same folder, create a docker-compose.yml file with your app config.

version: '3.9'
  my-app: # Should be exact same name as "id" field in config.json
    container_name: my-app # Should be exact same name as "id" field in config.json
    image: my-app:1.0.0 # Try to avoid "latest" tag. As it may break configs in the future.
      - TZ=${TZ} # Can use any env variable. List in runtipi/templates/env-sample
      - ${APP_DATA_DIR}/data/config:/config # Always start the path with ${APP_DATA_DIR}. This will put all data inside app-data/my-app/data
      - ${APP_DATA_DIR}/data/projects:/projects
      - ${APP_PORT}:8443
    restart: unless-stopped
      - tipi_main_network

You'll also need to create a metadata folder and inside put the following files:

  • - Long description of the app in markdown format. (see other apps for inspiration)
  • logo.jpg - Logo of the app in jpg format (512 x 512px) make sure the logo looks good in the dashboard

User defined environment variables

Sometimes an app is requiring more info to run it such as passwords or username. You can leverage the form_fields property in the config.json file to ask such information. Let's take for example Nextcloud. The image requires a username and password. We can simply add two fields in the config.json that will be presented to the user before installing.

  "form_fields": [
        "type": "text",
        "label": "Username",
        "max": 50,
        "min": 3,
        "required": true,
        "env_variable": "NEXTCLOUD_ADMIN_USER"
        "type": "password",
        "label": "Password",
        "max": 50,
        "min": 3,
        "required": true,
        "env_variable": "NEXTCLOUD_ADMIN_PASSWORD"

You can choose between different types of fields. The app will automatically validate the user input before submitting.

TypeDescriptionExample value
textJust a string of textusername
passwordWill be hidden on typingpassword
emailAn email
numberAny number123
fqdnFully qualified domain
ipAny valid ipv4 address192.168.2.100
fqdnipCombination between ip and fqdn192.168.2.100 or
randomGenerate a random value for the user2m3ffc0923rk93df9023f9
booleanA checkboxtrue or false

You can also define a min and max length of input with the corresponding properties. The env_variable property is the name of the variable you'll use in your docker-compose.yml file. Be sure to have a unique name.

When using the field type random for a password or secret, the min value will be used to determine the length of the string. If the min value is omitted the default length is 32 characters.

So if we take the Nextcloud example again, this is how you would use the form_fields inside your compose file.

version: '3.7'
    container_name: nextcloud
    image: nextcloud:23.0.3-apache
    restart: unless-stopped
      - ${APP_PORT}:80
      - ${APP_DATA_DIR}/data/nextcloud:/var/www/html

NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD are coming from the user inputs.

Regex validation

You can validate a user input against a regex:

  "env_variable": "version",
  "label": "Version",
  "pattern_error": "Version must be in the format x.y.z",
  "regex": "^[0-9]+.[0-9]+.[0-9]+$",
  "required": true,
  "type": "text"

The regex will be tested against the user input. If it doesn't match, the user will see the error message defined in pattern_error.

Multi select

You can also define a multi select field. This will be rendered as a dropdown in the UI.

  "label": "Select your favorite fruits",
  "type": "text",
  "required": true,
  "options": [
    { "label": "Apple", "value": "apple" },
    { "label": "Banana", "value": "banana" },
    { "label": "Orange", "value": "orange" }
  "env_variable": "fruits"

Default data folder

If your app requires default files or configuration, you can easily provide those by creating a data folder beside the app config.

        • config.json
        • docker-compose.yml
          • anything.conf
          • config.ini.template
          • logo.jpg
  • Anything placed under data will be copied over app-data/<app-id>/data before installation. Then you can mount those files inside your compose file.

      container_name: my-app
      restart: unless-stopped
        - ${APP_DATA_DIR}/data:/var/lib/config # Will mount the folder with `anything.conf` inside

    Using a template in your data folder

    If one of your files requires some dynamic values, you can use a template file. Let's take the example of a config.ini file that requires the APP_PORT variable.

    port = {{APP_PORT}}

    If you name your file config.ini.template, it will automatically replace the variables with the values defined in the environment variables.

    For example if you put the previous example in data/config.ini.template, it will be copied over to app-data/<app-id>/data/config.ini with the APP_PORT variable replaced.

    Per-architecture docker-compose files

    If your app requires different docker-compose files for different architectures, you can use the following naming convention:


    If the user is running on an arm64 architecture, this file will be used instead of the default docker-compose.yml.

    Commit your changes

    Once you're done, you can commit your changes to the repository.

    git add .
    git commit -m "Add my-app"
    git push origin master

    Submit a Pull Request

    You can now submit a pull request to the repository.

    • On GitHub, visit your repository and click on the "Pull requests" tab.
    • Click on "New pull request" and fill in the title and description.
    • Choose your branch and target the main repository at runtipi/runtipi-appstore.

    Test your app in your own instance

    Before submitting your app, you can test it in your own instance. You can do so by adding your app repository to the appsRepoUrl property in the settings.json file. Visit the Using your own appstore repo section to learn more.