KISS
, aka "Kir's Server Software", is a template project designed for aspiring self-hosters.
When you want to self-host something, it often involves spinning up a few Docker containers here, setting up some CRON jobs there, configuring a reverse proxy, and adding a few quick-and-dirty shell scripts on top of all that for good measure. Usually, you either have to set everything up manually or write a Bash script to handle it for you. Either way, you'll likely run into management challenges when you want to migrate to a new server, remove an existing service, or add a new one. This is where this project comes in.
KISS
is essentially a single shell script, kiss.sh
, that lets you easily split your service definitions into separate sub-projects. It also simplifies essential but tedious tasks like installing dependencies, setting up CRON jobs, creating reverse proxies, managing SSL certificates, and more.
To get started, fork (or just copy) this repo, customize the ./services/
directory to your needs and liking, and you're good to go!
Usage: kiss <command> [<options>] [<file>]
kiss ssh [-i <file>] <destination> <command> [<options>] [<file>]
Manage the deployment, backup, and recovery routines for the server software.
Examples:
kiss build -o ./build/kiss
kiss install
kiss backup -o backup.tar.gz
kiss restore backup.tar.gz
kiss ssh -i ~/.ssh/id_rsa root@42.42.42.42 recreate backup.tar.gz
Commands:
build [-o <build>] Build enabled services into a single executable
install Install built services
uninstall Uninstall built services
backup [-o <backup>] Backup each service via the "backup" command
restore <backup> Restore the state of services from a backup
recreate <backup> Install built services and then restore their state
<command> Execute the specified <command> for each service
Options:
-h, --help Display this help text and exit
-v, --version Display version information and exit
-q, --quiet Suppress all normal output
-e, --email Specify the ACME email address
-d, --domain Specify the domain name of the current machine
-o, --output <file> Write output to <file>
-i, --identity <file> Select the <file> from which the identity is read
Once you're done configuring your services (more on that later), it's time to package everything into a single file that can be distributed to the target server. To do this, use the build
command and optionally provide kiss.sh
with an output filename for the resulting executable:
./kiss.sh build -o ./kiss
If the build process completes successfully, you can find the executable representing the current state of the repo at the specified location (or ./build/kiss
if you didn't specify one) and move on to the next step.
After building KISS
, it can be distributed to the server where you'd like to install the configured services. Then, run:
./kiss install --domain "my-domain.if-any.net" --email "acme-email@if-any.net"
Congratulations! All the services should now be up and running.
Note: You only need to specify the domain name using the --domain
parameter if at least one of the configured services requires it. The same applies to the optional --email
parameter - only use it if one of your services needs an SSL certificate and you want to receive notifications when it's about to expire or if any other issue arises.
If you need to uninstall the configured services, run the following command on your server:
./kiss uninstall --domain "my-domain.if-any.net"
Note: You only need to provide the domain name via the --domain
parameter if you specified it during installation.
KISS
provides a simple way to create a combined backup for all your services. To do this, run the following command on your server:
./kiss backup --output "my-backup.tar.gz"
The backup file will be saved to the specified location. This file can then be used as input for the restore
command.
If you need to restore your services to a previously backed-up state, run the following command on your server:
./kiss restore "my-backup.tar.gz"
KISS
can run itself on a remote server by using the special ssh
command, which can be combined with the regular commands listed above. This means you don't have to worry about manually uploading it and its dependent files to a server, running it, or cleaning up afterward - KISS
will handle all of that for you, including uploading and downloading input and output files as needed. Here are some examples:
./kiss ssh -i ~/.ssh/id_rsa root@42.42.42.42 install -d "my-domain.if-any.net" -e "acme-email@if-any.net"
./kiss ssh -i ~/.ssh/id_rsa root@42.42.42.42 backup -o "backup.tar.gz"
./kiss ssh -i ~/.ssh/id_rsa root@42.42.42.42 restore "backup.tar.gz"
./kiss ssh -i ~/.ssh/id_rsa root@42.42.42.42 uninstall -d "my-domain.if-any.net"
The repository follows a pretty simple file structure to keep things clean and easy to manage:
# Contains reusable shell script files that provide
# shared functionality for your services.
libs/
<library-name>.sh
# Each subdirectory represents a managed service,
# with its configuration and scripts stored inside.
services/
<service-name>/
...
service.json
# The main script that manages the build, installation,
# and operation of your services.
kiss.sh
Each service should have its own directory in ./services/
with a service.json
file at its root.
The service.json
file is a metadata file required by KISS
, which provides information about how the service should be handled. For those familiar with Node.js' package.json
, service.json
follows a similar structure, so you'll likely find it pretty intuitive.
Let's walk through the most important fields:
A URI-friendly name for the service.
"name": "foo"
A SemVer-compliant version of the service.
"version": "1.0.0"
A dictionary of script commands that are run at various points in the service's lifecycle. The key is the lifecycle event, and the value is the command to execute at that stage.
To integrate with KISS
, your service may implement the following commands:
build
- if your service requires additional steps beforeKISS
is built.install
- for custom installation logic not covered byservice.json
.uninstall
- for custom uninstall logic.backup <output-filename>
- to create a backup of your service.restore <input-filename>
- to restore your service from a backup.
"scripts": {
"build": "./build.sh",
"preinstall": "echo Starting the installation...",
"install": "./install.sh",
"postinstall": "echo Finished the installation.",
"uninstall": "./uninstall.sh",
"backup": "./backup.sh \"$1\"",
"restore": "./restore.sh \"$1\""
}
A dictionary that specifies the files to be copied to the target machine during service installation. The key is the filename (relative to the service's root), and the value is the destination path on the target machine. You can also specify file permissions (as in chmod
), which default to rwxr-xr-x
if not provided.
Note: You can freely source other shell scripts from those listed in files
, and KISS
will handle this scenario for you.
"files": {
"backup.sh": "/usr/local/bin/foo-backup",
"restore.sh": ["/usr/local/bin/foo-restore", "rwxr-xr-x"]
}
A dictionary defining CRON jobs to be set up during service installation. The key is the job command, and the value is the CRON schedule.
"jobs": {
"/usr/local/bin/foo-backup": "0 0 * * *"
}
A dictionary for defining reverse proxies that should be set up when the service is installed. The key is the publicly accessible server URI, and the value is the backend service URI to redirect requests to.
- The server URI defaults to
https://
, and the backend URI defaults tohttp://
if the protocol is omitted. - If your server uses
https://
,KISS
will automatically fetch SSL certificates from Let's Encrypt. - You can use
*
in place of the domain name. For server URIs,KISS
will replace*
with the domain specified via the--domain
parameter, while for backend URIs,*
typically resolves tolocalhost
.
"proxies": {
"foo.*": "*:1234",
"http://bar.*": "*:1235"
}
An array of system packages that should be installed when the service is being installed.
"dependencies": [
"docker",
"jq"
]
An array of system packages that should be installed when the service is being built.
"devDependencies": [
"docker",
"jq"
]
This template comes with a few preconfigured services to showcase how KISS
works. These examples can be used as-is or customized for your own needs:
-
certbot
: A service that automates the renewal of SSL certificates using the EFF's Certbot tool. -
outline-server
: A self-hosted VPN server designed to provide secure internet access. With Outline, you can easily manage your own VPN, allowing users to enjoy encrypted communication and bypass censorship and/or geo-restrictions. -
telegram-bot
: A custom Telegram bot designed to manage the Outline Server, providing an easy way to interact with and control your VPN through Telegram. While it's built withoutline-server
in mind, this bot is fully extensible, so you can modify it to handle any task you want. -
watchtower
: A lightweight service that automatically updates your Docker containers. Watchtower monitors your running Docker services and, if a new version of a container image is available, it will seamlessly pull the update and restart the service for you.
In addition to the standard CI jobs that facilitate the maintenance of the project by automatically building KISS
whenever you push a new commit or create a new release, this repository includes a few additional workflows: install
, reinstall
, and backup
. These jobs are designed to help you deploy your KISS
instance directly to your server via SSH, and even maintain backups of your services!
To enable these workflows, you need to configure the following secrets and variables:
Name | Type | Default | Description |
---|---|---|---|
KISS_DOMAIN |
Secret | N/A | The domain name associated with the remote server. |
KISS_EMAIL |
Secret | (none) | The email address registered for ACME services. |
SSH_USER |
Secret | root |
The username used to log into the remote server via SSH. This should have appropriate privileges to install or manage services. |
SSH_HOST |
Secret | N/A | The IP address or domain of the remote server where the KISS instance and its services will be deployed or managed. |
SSH_PRIVATE_KEY |
Secret | N/A | The private SSH key used to authenticate with the remote server. This key allows secure, passwordless login when paired with the corresponding public key on the server. |
BACKUP_KEY |
Secret | N/A | A key used to encrypt backups. This ensures that backups created by the system are securely encrypted before being stored or transferred. |
BACKUP_RETENTION_DAYS |
Variable | 90 |
The number of days to retain the backups. After this period, older backups will be automatically deleted. |
With this information in place, KISS
will be able to install or reinstall your services on the specified server whenever you dispatch install
or reinstall
jobs, respectively. Additionally, it will begin creating automated encrypted backups of your services through scheduled (or manual) dispatches of the backup
job.
Licensed under the terms of the MIT License.