Community maintained Docker config for the spindle server

Compare changes

Choose any two refs to compare.

Changed files
+150 -105
rootfs
etc
s6-overlay
s6-rc.d
create-sshd-host-keys
knotserver
dependencies.d
run
spindleserver
dependencies.d
run
sshd
user
scripts
ssh
sshd_config.d
+1
.gitignore
···
+
.DS_Store
+30 -34
Dockerfile
···
-
FROM docker.io/golang:1.24-alpine3.21 AS build
-
+
FROM golang:1.24-alpine AS builder
ENV CGO_ENABLED=1
-
ENV KNOT_REPO_SCAN_PATH=/home/git/repositories
-
WORKDIR /usr/src/app
-
COPY go.mod go.sum ./
-
RUN apk add --no-cache gcc musl-dev
-
RUN go mod download
+
ARG TAG='v1.10.0-alpha'
-
COPY . .
-
RUN go build -v \
-
-o /usr/local/bin/knot \
-
-ldflags='-s -w -extldflags "-static"' \
-
./cmd/knot
+
WORKDIR /app
+
RUN apk add git gcc musl-dev
+
RUN git clone -b ${TAG} https://tangled.org/@tangled.org/core .
+
RUN go build -o /usr/bin/spindle -ldflags '-s -w -extldflags "-static"' ./cmd/spindle
-
FROM docker.io/alpine:3.21
+
FROM alpine:edge
-
LABEL org.opencontainers.image.title=Tangled
-
LABEL org.opencontainers.image.description="Tangled is a decentralized and open code collaboration platform, built on atproto."
-
LABEL org.opencontainers.image.vendor=Tangled.sh
-
LABEL org.opencontainers.image.licenses=MIT
-
LABEL org.opencontainers.image.url=https://tangled.sh
-
LABEL org.opencontainers.image.source=https://tangled.sh/@tangled.sh/core
+
ARG PORT=6555
+
EXPOSE $PORT
-
RUN apk add --no-cache shadow s6-overlay execline openssh git curl && \
-
adduser --disabled-password git && \
-
# We need to set password anyway since otherwise ssh won't work
-
head -c 32 /dev/random | base64 | tr -dc 'a-zA-Z0-9' | passwd git --stdin && \
-
mkdir /app && mkdir /home/git/repositories
+
LABEL org.opencontainers.image.title='spindle'
+
LABEL org.opencontainers.image.description='CI runner for tangled'
+
LABEL org.opencontainers.image.source='https://tangled.org/@keea.dog/spindle-docker'
+
LABEL org.opencontainers.image.url='https://tangled.org'
+
LABEL org.opencontainers.image.vendor='tangled.org'
+
LABEL org.opencontainers.image.licenses='MIT'
-
COPY --from=build /usr/local/bin/knot /usr/local/bin
-
COPY docker/rootfs/ .
-
RUN chmod +x /etc/s6-overlay/scripts/keys-wrapper && \
-
chown git:git /app && \
-
chown -R git:git /home/git/repositories
+
ARG UID=1000
+
ARG GID=1000
-
EXPOSE 22
-
EXPOSE 5555
+
COPY rootfs .
+
RUN chmod 755 /etc
+
RUN chmod -R 755 /etc/s6-overlay
+
RUN apk add shadow s6-overlay execline openssl curl
+
RUN groupadd -g $GID -f spindle
+
RUN useradd -u $UID -g $GID -d /home/spindle spindle
+
RUN openssl rand -hex 16 | passwd --stdin spindle
+
RUN mkdir -p /home/spindle/repositories && chown -R spindle:spindle /home/spindle
+
COPY --from=builder /usr/bin/spindle /usr/bin
+
RUN mkdir /app && chown -R spindle:spindle /app
-
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
-
CMD curl -f http://localhost:5555/ || exit 1
+
HEALTHCHECK --interval=60s --timeout=30s --start-period=5s --retries=3 \
+
CMD curl -f http://localhost:${PORT} || exit 1
-
ENTRYPOINT ["/init"]
+
ENTRYPOINT ["/init"]
+22 -20
docker-compose.yml
···
services:
-
knot:
+
spindle:
build:
-
context: ..
-
dockerfile: docker/Dockerfile
+
context: .
+
args:
+
UID: 1000
+
GID: 1000
+
PORT: ${INTERNAL_PORT:-6555}
environment:
-
KNOT_SERVER_HOSTNAME: ${KNOT_SERVER_HOSTNAME}
-
KNOT_SERVER_SECRET: ${KNOT_SERVER_SECRET}
-
KNOT_SERVER_DB_PATH: "/app/knotserver.db"
-
KNOT_REPO_SCAN_PATH: "/home/git/repositories"
-
KNOT_SERVER_INTERNAL_LISTEN_ADDR: "localhost:5444"
+
SPINDLE_SERVER_HOSTNAME: ${SPINDLE_SERVER_HOSTNAME}
+
SPINDLE_SERVER_OWNER: ${SPINDLE_SERVER_OWNER}
+
SPINDLE_SERVER_DB_PATH: /app/spindle.db
+
SPINDLE_SERVER_LISTEN_ADDR: localhost:6555
+
SPINDLE_PIPELINES_LOG_DIR: /var/log/spindle
+
PORT: ${INTERNAL_PORT:-6555}
volumes:
-
- "./keys:/etc/ssh/keys"
-
- "./repositories:/home/git/repositories"
-
- "./server:/app"
+
- ./server:/app
+
- /var/run/docker.sock:/var/run/docker.sock
ports:
-
- "5555:5555"
-
- "2222:22"
+
- "${INTERNAL_PORT:-6555}:${INTERNAL_PORT:-6555}"
restart: always
frontend:
-
image: caddy:2-alpine
+
image: caddy:alpine
command: >
caddy
reverse-proxy
-
--from ${KNOT_SERVER_HOSTNAME}
-
--to knot:5555
+
--from ${SPINDLE_SERVER_HOSTNAME}
+
--to spindle:6555
depends_on:
-
- knot
+
- spindle
ports:
-
- "${KNOT_SERVER_PORT:-443}:443"
-
- "${KNOT_SERVER_PORT:-443}:443/udp"
+
- ${SPINDLE_SERVER_PORT:-443}:443
+
- ${SPINDLE_SERVER_PORT:-443}:443/udp
volumes:
-
- caddy_data:/data
+
- ./caddy_data:/data
restart: always
profiles: ["caddy"]
+22
license.txt
···
+
MIT License
+
+
Copyright (c) 2025 Tangled Team
+
+
Permission is hereby granted, free of charge, to any person obtaining a copy
+
of this software and associated documentation files (the "Software"), to deal
+
in the Software without restriction, including without limitation the rights
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+
copies of the Software, and to permit persons to whom the Software is
+
furnished to do so, subject to the following conditions:
+
+
The above copyright notice and this permission notice shall be included in all
+
copies or substantial portions of the Software.
+
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+
SOFTWARE.
+
+71 -3
readme.md
···
-
# knot-docker
+
# Knot Docker
+
+
> **IMPORTANT**
+
> This is a community maintained repository, support is not guaranteed.
+
+
Docker container and compose setup to run a [Tangled](https://tangled.org) knot
+
and host your own repository data.
+
+
## Pre-built Images
+
+
There is a [repository](https://hub.docker.com/r/tngl/knot) of pre-built images
+
for tags starting at `v1.8.0-alpha` if you prefer.
+
+
```
+
docker pull tngl/knot:v1.10.0-alpha
+
```
+
+
Note that these are *not* official images, you use them at your own risk.
+
+
## Building The Image
+
+
By default the `Dockerfile` will build the latest tag, but you can change it
+
with the `TAG` build argument.
-
This is a community maintained Docker setup for hosting your own knot
-
server.
+
```sh
+
docker build -t knot:latest --build-arg TAG=master .
+
```
+
+
The command above for example will build the latest commit on the `master`
+
branch.
+
+
By default it will also create a `git` user with user and group ID 1000:1000,
+
but you can change it with the `UID` and `GID` build arguments.
+
+
```sh
+
docker build -t knot:latest --build-arg UID=$(id -u) GID=$(id -g)
+
```
+
+
The command above for example will create a user with the host user's UID and GID.
+
This is useful if you are bind mounting the repositories and app folder on the host,
+
as in the provided `docker-compose.yml` file.
+
+
<hr style="margin-bottom: 20px; margin-top: 10px" />
+
+
When using compose, these can be specified as build arguments which will be
+
passed to the builder.
+
+
```yaml
+
build:
+
context: .
+
args:
+
TAG: master
+
UID: 1000
+
GID: 1000
+
```
+
+
This will for example tell docker to build it using the `master` branch like
+
the command.
+
+
## Setting Up The Image
+
+
The simplest way to set up your own knot is to use the provided compose file
+
and run the following:
+
+
```sh
+
export KNOT_SERVER_HOSTNAME=example.com
+
export KNOT_SERVER_OWNER=did:plc:yourdidgoeshere
+
export KNOT_SERVER_PORT=443
+
docker compose up -d
+
```
+
+
This will setup everything for you including a reverse proxy.
-1
rootfs/etc/s6-overlay/s6-rc.d/create-sshd-host-keys/type
···
-
oneshot
-1
rootfs/etc/s6-overlay/s6-rc.d/create-sshd-host-keys/up
···
-
/etc/s6-overlay/scripts/create-sshd-host-keys
rootfs/etc/s6-overlay/s6-rc.d/knotserver/dependencies.d/base

This is a binary file and will not be displayed.

-3
rootfs/etc/s6-overlay/s6-rc.d/knotserver/run
···
-
#!/command/with-contenv ash
-
-
exec s6-setuidgid git /usr/local/bin/knot server
-1
rootfs/etc/s6-overlay/s6-rc.d/knotserver/type
···
-
longrun
rootfs/etc/s6-overlay/s6-rc.d/spindleserver/dependencies.d/base

This is a binary file and will not be displayed.

+3
rootfs/etc/s6-overlay/s6-rc.d/spindleserver/run
···
+
#!/command/with-contenv ash
+
+
exec s6-setuidgid spindle /usr/bin/spindle server
+1
rootfs/etc/s6-overlay/s6-rc.d/spindleserver/type
···
+
longrun
rootfs/etc/s6-overlay/s6-rc.d/sshd/dependencies.d/base

This is a binary file and will not be displayed.

rootfs/etc/s6-overlay/s6-rc.d/sshd/dependencies.d/create-sshd-host-keys

This is a binary file and will not be displayed.

-3
rootfs/etc/s6-overlay/s6-rc.d/sshd/run
···
-
#!/usr/bin/execlineb -P
-
-
/usr/sbin/sshd -e -D
-1
rootfs/etc/s6-overlay/s6-rc.d/sshd/type
···
-
longrun
rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/knotserver

This is a binary file and will not be displayed.

rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/spindleserver

This is a binary file and will not be displayed.

rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/sshd

This is a binary file and will not be displayed.

-21
rootfs/etc/s6-overlay/scripts/create-sshd-host-keys
···
-
#!/usr/bin/execlineb -P
-
-
foreground {
-
if -n { test -d /etc/ssh/keys }
-
mkdir /etc/ssh/keys
-
}
-
-
foreground {
-
if -n { test -f /etc/ssh/keys/ssh_host_rsa_key }
-
ssh-keygen -t rsa -f /etc/ssh/keys/ssh_host_rsa_key -q -N ""
-
}
-
-
foreground {
-
if -n { test -f /etc/ssh/keys/ssh_host_ecdsa_key }
-
ssh-keygen -t rsa -f /etc/ssh/keys/ssh_host_ecdsa_key -q -N ""
-
}
-
-
foreground {
-
if -n { test -f /etc/ssh/keys/ssh_host_ed25519_key }
-
ssh-keygen -t rsa -f /etc/ssh/keys/ssh_host_ed25519_key -q -N ""
-
}
-8
rootfs/etc/s6-overlay/scripts/keys-wrapper
···
-
#!/bin/sh
-
-
# Execute the knot keys command with proper shell context
-
exec /bin/sh -c '/usr/local/bin/knot keys \
-
-output authorized-keys \
-
-internal-api "http://${KNOT_SERVER_INTERNAL_LISTEN_ADDR:-localhost:5444}" \
-
-git-dir "${KNOT_REPO_SCAN_PATH:-/home/git/repositories}" \
-
-log-path "/tmp/knotguard.log"'
-9
rootfs/etc/ssh/sshd_config.d/tangled_sshd.conf
···
-
HostKey /etc/ssh/keys/ssh_host_rsa_key
-
HostKey /etc/ssh/keys/ssh_host_ecdsa_key
-
HostKey /etc/ssh/keys/ssh_host_ed25519_key
-
-
PasswordAuthentication no
-
-
Match User git
-
AuthorizedKeysCommand /etc/s6-overlay/scripts/keys-wrapper
-
AuthorizedKeysCommandUser nobody