1# Soft Serve
  2
  3<p>
  4    <img style="width: 451px" src="https://stuff.charm.sh/soft-serve/soft-serve-header.png?0" alt="A nice rendering of some melting ice cream with the words āCharm Soft Serveā next to it"><br>
  5    <a href="https://github.com/charmbracelet/soft-serve/releases"><img src="https://img.shields.io/github/release/charmbracelet/soft-serve.svg" alt="Latest Release"></a>
  6    <a href="https://pkg.go.dev/github.com/charmbracelet/soft-serve?tab=doc"><img src="https://godoc.org/github.com/golang/gddo?status.svg" alt="GoDoc"></a>
  7    <a href="https://github.com/charmbracelet/soft-serve/actions"><img src="https://github.com/charmbracelet/soft-serve/workflows/build/badge.svg" alt="Build Status"></a>
  8    <a href="https://nightly.link/charmbracelet/soft-serve/workflows/nightly/main"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=appveyor"/></a>
  9</p>
 10
 11A tasty, self-hostable Git server for the command line. š¦
 12
 13<picture>
 14  <source media="(max-width: 750px)" srcset="https://stuff.charm.sh/soft-serve/soft-serve-demo.gif?0">
 15  <source media="(min-width: 750px)" width="750" srcset="https://stuff.charm.sh/soft-serve/soft-serve-demo.gif?0">
 16  <img src="https://stuff.charm.sh/soft-serve/soft-serve-demo.gif?0" alt="Soft Serve screencast">
 17</picture>
 18
 19- Easy to navigate TUI available over SSH
 20- Clone repos over SSH, HTTP, or Git protocol
 21- Manage repos with SSH
 22- Create repos on demand with SSH or `git push`
 23- Browse repos, files and commits with SSH-accessible
 24- Print files over SSH with or without syntax highlighting and line numbers
 25- Easy access control with SSH
 26  - Allow/disallow anonymous access
 27  - Add collaborators with SSH public keys
 28  - Repos can be public or private
 29
 30## Where can I see it?
 31
 32Just run `ssh git.charm.sh` for an example. You can also try some of the following commands:
 33
 34```bash
 35# Jump directly to a repo in the TUI
 36ssh git.charm.sh -t soft-serve
 37
 38# Print out a directory tree for a repo
 39ssh git.charm.sh repo tree soft-serve
 40
 41# Print a specific file
 42ssh git.charm.sh repo blob soft-serve cmd/soft/root.go
 43
 44# Print a file with syntax highlighting and line numbers
 45ssh git.charm.sh repo blob soft-serve cmd/soft/root.go -c -l
 46```
 47
 48## Installation
 49
 50Soft Serve is a single binary called `soft`. You can get it from a package
 51manager:
 52
 53```bash
 54# macOS or Linux
 55brew tap charmbracelet/tap && brew install charmbracelet/tap/soft-serve
 56
 57# Arch Linux
 58pacman -S soft-serve
 59
 60# Nix
 61nix-env -iA nixpkgs.soft-serve
 62
 63# Debian/Ubuntu
 64sudo mkdir -p /etc/apt/keyrings
 65curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg
 66echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list
 67sudo apt update && sudo apt install soft-serve
 68
 69# Fedora/RHEL
 70echo '[charm]
 71name=Charm
 72baseurl=https://repo.charm.sh/yum/
 73enabled=1
 74gpgcheck=1
 75gpgkey=https://repo.charm.sh/yum/gpg.key' | sudo tee /etc/yum.repos.d/charm.repo
 76sudo yum install soft-serve
 77```
 78
 79You can also download a binary from the [releases][releases] page. Packages are
 80available in Alpine, Debian, and RPM formats. Binaries are available for Linux,
 81macOS, and Windows.
 82
 83[releases]: https://github.com/charmbracelet/soft-serve/releases
 84
 85Or just install it with `go`:
 86
 87```bash
 88go install github.com/charmbracelet/soft-serve/cmd/soft@latest
 89```
 90
 91## Setting up a server
 92
 93Make sure `git` is installed, then run `soft serve`. Thatās it.
 94
 95This will create a `data` directory that will store all the repos, ssh keys,
 96and database.
 97
 98To change the default data path use `SOFT_SERVE_DATA_PATH` environment variable.
 99
100```sh
101SOFT_SERVE_DATA_PATH=/var/lib/soft-serve soft serve
102```
103
104When you run Soft Serve for the first time, make sure you have the
105`SOFT_SERVE_INITIAL_ADMIN_KEY` environment variable is set to your ssh
106authorized key. Any added key to this variable will be treated as admin with
107full privileges.
108
109Using this environment variable, Soft Serve will create a new `admin` user that
110has full privileges. You can rename and change the user settings later.
111
112### Server Settings
113
114Once you start the server for the first time, the settings will be in
115`config.yaml` under your data directory. The default `config.yaml` is
116self-explanatory and will look like this:
117
118```yaml
119# Soft Serve Server configurations
120
121# The name of the server.
122# This is the name that will be displayed in the UI.
123name: "Soft Serve"
124
125# The SSH server configuration.
126ssh:
127  # The address on which the SSH server will listen.
128  listen_addr: ":23231"
129
130  # The public URL of the SSH server.
131  # This is the address that will be used to clone repositories.
132  public_url: "ssh://localhost:23231"
133
134  # The path to the SSH server's private key.
135  key_path: "ssh/soft_serve_host"
136
137  # The path to the SSH server's client private key.
138  # This key will be used to authenticate the server to make git requests to
139  # ssh remotes.
140  client_key_path: "ssh/soft_serve_client"
141
142  # The path to the SSH server's internal api private key.
143  internal_key_path: "ssh/soft_serve_internal"
144
145  # The maximum number of seconds a connection can take.
146  # A value of 0 means no timeout.
147  max_timeout: 0
148
149  # The number of seconds a connection can be idle before it is closed.
150  idle_timeout: 120
151
152# The Git daemon configuration.
153git:
154  # The address on which the Git daemon will listen.
155  listen_addr: ":9418"
156
157  # The maximum number of seconds a connection can take.
158  # A value of 0 means no timeout.
159  max_timeout: 0
160
161  # The number of seconds a connection can be idle before it is closed.
162  idle_timeout: 3
163
164  # The maximum number of concurrent connections.
165  max_connections: 32
166
167# The HTTP server configuration.
168http:
169  # The address on which the HTTP server will listen.
170  listen_addr: ":8080"
171
172  # The path to the TLS private key.
173  tls_key_path: ""
174
175  # The path to the TLS certificate.
176  tls_cert_path: ""
177
178  # The public URL of the HTTP server.
179  # This is the address that will be used to clone repositories.
180  # Make sure to use https:// if you are using TLS.
181  public_url: "http://localhost:8080"
182
183# The stats server configuration.
184stats:
185  # The address on which the stats server will listen.
186  listen_addr: ":8081"
187
188# Additional admin keys.
189#initial_admin_keys:
190#  - "ssh-rsa AAAAB3NzaC1yc2..."
191
192```
193
194You can also use environment variables, to override these settings. All server
195settings environment variables start with `SOFT_SERVE_` followed by the setting
196name all in uppercase. Here are some examples:
197
198- `SOFT_SERVE_NAME`: The name of the server that will appear in the TUI
199- `SOFT_SERVE_SSH_LISTEN_ADDR`: SSH listen address
200- `SOFT_SERVE_SSH_KEY_PATH`: SSH host key-pair path
201- `SOFT_SERVE_HTTP_LISTEN_ADDR`: HTTP listen address
202- `SOFT_SERVE_HTTP_PUBLIC_URL`: HTTP public URL used for cloning
203- `SOFT_SERVE_GIT_MAX_CONNECTIONS`: The number of simultaneous connections to git daemon
204
205A [Docker image][docker] is also available.
206
207[docker]: https://github.com/charmbracelet/soft-serve/blob/main/docker.md
208
209## Configuration
210
211Configuring Soft Serve is simple and straightforward. Use the SSH command-line
212interface to manage access settings, users, and repos.
213
214For more info try `ssh localhost -i ~/.ssh/id_ed25519 -p 23231 help`. Make sure
215you use your key here.
216
217> **Note** The `-i` part will be omitted in the examples below for brevity. You
218> can add your server settings to your sshconfig for quicker access.
219
220### Access Levels
221
222Soft Serve offers a simple access control. There are four access levels,
223no-access, read-only, read-write, and admin-access.
224
225`admin-access` has full control of the server and can make changes to users and repos.
226
227`read-write` access gets full control of repos.
228
229`read-only` can read public repos.
230
231`no-access` denies access to all repos.
232
233### Authentication
234
235Everything that needs authentication is done using SSH.
236
237By default, Soft Serve gives ready-only permission to anonymous connections to
238any of the above protocols. This is controlled by two settings `anon-access`
239and `allow-keyless`.
240
241- `anon-access`: Defines the access level for anonymous users. Available
242  options are `no-access`, `read-only`, `read-write`, and `admin-access`.
243  Default is `read-only`.
244- `allow-keyless`: Whether to allow connections that doesn't use keys to pass.
245  Setting this to `false` would disable access to SSH keyboard-interactive,
246  HTTP, and Git protocol connections. Default is `true`.
247
248```sh
249$ ssh localhost settings
250Manage server settings
251
252Usage:
253  ssh -p 23231 localhost settings [command]
254
255Available Commands:
256  allow-keyless Set or get allow keyless access to repositories
257  anon-access   Set or get the default access level for anonymous users
258
259Flags:
260  -h, --help   help for settings
261
262Use "ssh -p 23231 localhost settings [command] --help" for more information about a command.
263```
264
265> **Note** These settings can only be changed by admins.
266
267When `allow-keyless` is disabled, connections that don't use SSH Public Key
268authentication will get denied. This means cloning repos over HTTP(s) or git://
269will get denied.
270
271Meanwhile, `anon-access` controls the access level granted to connections that
272use SSH Public Key authentication but are not registered users. The default
273setting for this is `read-only`. This will grant anonymous connections that use
274SSH Public Key authentication `read-only` access to public repos.
275
276## Authorization
277
278Admins can manage users and manage their keys. Once a user is created and has
279access to the server, they can manage their own keys and settings.
280
281To create a new user simply use `user create`:
282
283```sh
284# Create a new user
285ssh -p 23231 localhost user create beatrice
286
287# Add user keys
288ssh -p 23231 localhost user add-pubkey beatrice ssh-rsa AAAAB3Nz...
289ssh -p 23231 localhost user add-pubkey beatrice ssh-ed25519 AAAA...
290
291# Create another user with public key
292ssh -p 23231 localhost user create frankie '-k "ssh-ed25519 AAAATzN..."'
293
294# Need help?
295ssh -p 23231 localhost user help
296```
297
298Once a user has access, they get `read-only` access to public repositories.
299They can also create new repositories on the server.
300
301Non-admin users can manage their keys using the `pubkey` command:
302
303```sh
304# List user keys
305ssh -p 23231 localhost pubkey list
306
307# Add key
308ssh -p 23231 localhost pubkey add ssh-ed25519 AAAA...
309
310# Wanna change your username?
311ssh -p 23231 localhost set-username yolo
312
313# To display user info
314ssh -p 23231 localhost info
315```
316
317## Repositories
318
319You can manage repositories using the `repo` command.
320
321```sh
322# Run repo help
323$ ssh -p 23231 localhost repo help
324Manage repositories
325
326Usage:
327  ssh -p 23231 localhost repo [command]
328
329Aliases:
330  repo, repos, repository, repositories
331
332Available Commands:
333  blob         Print out the contents of file at path
334  branch       Manage repository branches
335  collab       Manage collaborators
336  create       Create a new repository
337  delete       Delete a repository
338  description  Set or get the description for a repository
339  hide         Hide or unhide a repository
340  import       Import a new repository from remote
341  info         Get information about a repository
342  is-mirror    Whether a repository is a mirror
343  list         List repositories
344  private      Set or get a repository private property
345  project-name Set or get the project name for a repository
346  rename       Rename an existing repository
347  tag          Manage repository tags
348  tree         Print repository tree at path
349
350Flags:
351  -h, --help   help for repo
352
353Use "ssh -p 23231 localhost repo [command] --help" for more information about a command.
354```
355
356### Creating Repositories
357
358To create a repository, first make sure you are an admin or a registered user.
359Use the `repo create <repo>` command to create a new repository:
360
361```sh
362# Create a new repository
363ssh -p 23231 localhost repo create icecream
364
365# Create a repo with description
366ssh -p 23231 localhost repo create icecream '-d "This is an Ice Cream description"'
367
368# ... and project name
369ssh -p 23231 localhost repo create icecream '-d "This is an Ice Cream description"' '-n "Ice Cream"'
370
371# I need my repository private!
372ssh -p 23231 localhost repo create icecream -p '-d "This is an Ice Cream description"' '-n "Ice Cream"'
373
374# Help?
375ssh -p 23231 localhost repo create -h
376```
377
378Or you can add your Soft Serve server as a remote to any existing repo, given
379you have write access, and push to remote:
380
381```
382git remote add origin ssh://localhost:23231/icecream
383```
384
385After youāve added the remote just go ahead and push. If the repo doesnāt exist
386on the server itāll be created.
387
388```
389git push origin main
390```
391
392Repositories can be nested too:
393
394```sh
395# Create a new nested repository
396ssh -p 23231 localhost repo create charmbracelet/icecream
397
398# Or ...
399git remote add charm ssh://localhost:23231/charmbracelet/icecream
400git push charm main
401```
402
403### Deleting Repositories
404
405You can delete repositories using the `repo delete <repo>` command.
406
407```sh
408ssh -p 23231 localhost repo delete icecream
409```
410
411### Renaming Repositories
412
413Use the `repo rename <old> <new>` command to rename existing repositories.
414
415```sh
416ssh -p 23231 localhost repo rename icecream vanilla
417```
418
419### Repository Collaborators
420
421Sometimes you want to restrict write access to certain repositories. This can
422be achieved by adding a collaborator to your repository.
423
424Use the `repo collab <command> <repo>` command to manage repo collaborators.
425
426```sh
427# Add collaborator to soft-serve
428ssh -p 23231 localhost repo collab add soft-serve frankie
429
430# Remove collaborator
431ssh -p 23231 localhost repo collab remove soft-serve beatrice
432
433# List collaborators
434ssh -p 23231 localhost repo collab list soft-serve
435```
436
437### Repository metadata
438
439You can also change the repo's description, project name, whether it's private,
440etc using the `repo <command>` command.
441
442```sh
443# Set description for repo
444ssh -p 23231 localhost repo description icecream "This is a new description"
445
446# Hide repo from listing
447ssh -p 23231 localhost repo hidden icecream true
448
449# List repository info (branches, tags, description, etc)
450ssh -p 23231 localhost repo icecream info
451```
452
453To make a repository private, use `repo private <repo> [true|false]`. Private
454repos can only be accessed by admins and collaborators.
455
456```sh
457ssh -p 23231 localhost repo icecream private true
458```
459
460### Repository Branches & Tags
461
462Use `repo branch` and `repo tag` to list, and delete branches or tags. You can
463also use `repo branch default` to set or get the repository default branch.
464
465### Repository Tree
466
467To print a file tree for the project, just use the `repo tree` command along with
468the repo name as the SSH command to your Soft Serve server:
469
470```sh
471ssh -p 23231 localhost repo tree soft-serve
472```
473
474You can also specify the sub-path and a specific reference or branch.
475
476```sh
477ssh -p 23231 localhost repo tree soft-serve server/config
478ssh -p 23231 localhost repo tree soft-serve main server/config
479```
480
481From there, you can print individual files using the `repo blob` command:
482
483```sh
484ssh -p 23231 localhost repo blob soft-serve cmd/soft/root.go
485```
486
487You can add the `-c` flag to enable syntax coloring and `-l` to print line
488numbers:
489
490```sh
491ssh -p 23231 localhost repo blob soft-serve cmd/soft/root.go -c -l
492
493```
494
495Use `--raw` to print raw file contents. This is useful for dumping binary data.
496
497## The Soft Serve TUI
498
499<img src="https://stuff.charm.sh/soft-serve/soft-serve-demo-commit.png" width="750" alt="TUI example showing a diff">
500
501Soft Serve serves a TUI over SSH for browsing repos, viewing files and commits,
502and grabbing clone commands:
503
504```sh
505ssh localhost -p 23231
506```
507
508It's also possible to ālinkā to a specific repo:
509
510```sh
511ssh -p 23231 localhost -t soft-serve
512```
513
514You can copy text to your clipboard over SSH. For instance, you can press
515<kbd>c</kbd> on the highlighted repo in the menu to copy the clone command
516[^osc52].
517
518[^osc52]:
519    Copying over SSH depends on your terminal support of OSC52. Refer to
520    [go-osc52](https://github.com/aymanbagabas/go-osc52) for more information.
521
522## A note about RSA keys
523
524Unfortunately, due to a shortcoming in Goās `x/crypto/ssh` package, Soft Serve
525does not currently support access via new SSH RSA keys: only the old SHA-1
526ones will work.
527
528Until we sort this out youāll either need an SHA-1 RSA key or a key with
529another algorithm, e.g. Ed25519. Not sure what type of keys you have?
530You can check with the following:
531
532```sh
533$ find ~/.ssh/id_*.pub -exec ssh-keygen -l -f {} \;
534```
535
536If youāre curious about the inner workings of this problem have a look at:
537
538- https://github.com/golang/go/issues/37278
539- https://go-review.googlesource.com/c/crypto/+/220037
540- https://github.com/golang/crypto/pull/197
541
542## Feedback
543
544Weād love to hear your thoughts on this project. Feel free to drop us a note!
545
546- [Twitter](https://twitter.com/charmcli)
547- [The Fediverse](https://mastodon.social/@charmcli)
548- [Discord](https://charm.sh/chat)
549
550## License
551
552[MIT](https://github.com/charmbracelet/soft-serve/raw/main/LICENSE)
553
554---
555
556Part of [Charm](https://charm.sh).
557
558<a href="https://charm.sh/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-badge.jpg" width="400"></a>
559
560Charmēē±å¼ęŗ ⢠Charm loves open source