1
+# syntax=docker/dockerfile:1
2
+# Enables BuildKit with cache mounts for faster builds
3
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.25 AS builder
4
5
ARG TARGETOS TARGETARCH
6
7
ENV SRC_DIR=/kubo
8
7
-# Download packages first so they can be cached.
9
+# Cache go module downloads between builds for faster rebuilds
10
COPY go.mod go.sum $SRC_DIR/
9
-RUN cd $SRC_DIR \
11
+RUN --mount=type=cache,target=/go/pkg/mod \
12
+ cd $SRC_DIR \
13
&& go mod download
14
15
COPY . $SRC_DIR
21
# Allow for other targets to be built, e.g.: docker build --build-arg MAKE_TARGET="nofuse"
22
ARG MAKE_TARGET=build
23
21
-# Build the thing.
22
-# Also: fix getting HEAD commit hash via git rev-parse.
23
-RUN cd $SRC_DIR \
24
+# Build ipfs binary with cached go modules and build cache.
25
+# mkdir .git/objects allows git rev-parse to read commit hash for version info
26
+RUN --mount=type=cache,target=/go/pkg/mod \
27
+ --mount=type=cache,target=/root/.cache/go-build \
28
+ cd $SRC_DIR \
29
&& mkdir -p .git/objects \
30
&& GOOS=$TARGETOS GOARCH=$TARGETARCH GOFLAGS=-buildvcs=false make ${MAKE_TARGET} IPFS_PLUGINS=$IPFS_PLUGINS
31
27
-# Using Debian Buster because the version of busybox we're using is based on it
28
-# and we want to make sure the libraries we're using are compatible. That's also
29
-# why we're running this for the target platform.
32
+# Extract required runtime tools from Debian.
33
+# We use Debian instead of Alpine because we need glibc compatibility
34
+# for the busybox base image we're using.
35
FROM debian:bookworm-slim AS utilities
36
RUN set -eux; \
37
apt-get update; \
33
- apt-get install -y \
38
+ apt-get install -y --no-install-recommends \
39
tini \
40
# Using gosu (~2MB) instead of su-exec (~20KB) because it's easier to
41
# install on Debian. Useful links:
42
# - https://github.com/ncopa/su-exec#why-reinvent-gosu
43
# - https://github.com/tianon/gosu/issues/52#issuecomment-441946745
44
gosu \
40
- # This installs fusermount which we later copy over to the target image.
45
+ # fusermount enables IPFS mount commands
46
fuse \
47
ca-certificates \
48
; \
44
- rm -rf /var/lib/apt/lists/*
49
+ apt-get clean; \
50
+ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
51
46
-# Now comes the actual target image, which aims to be as small as possible.
52
+# Final minimal image with shell for debugging (busybox provides sh)
53
FROM busybox:stable-glibc
54
49
-# Get the ipfs binary, entrypoint script, and TLS CAs from the build container.
55
+# Copy ipfs binary, startup scripts, and runtime dependencies
56
ENV SRC_DIR=/kubo
57
COPY --from=utilities /usr/sbin/gosu /sbin/gosu
58
COPY --from=utilities /usr/bin/tini /sbin/tini
59
COPY --from=utilities /bin/fusermount /usr/local/bin/fusermount
60
COPY --from=utilities /etc/ssl/certs /etc/ssl/certs
61
COPY --from=builder $SRC_DIR/cmd/ipfs/ipfs /usr/local/bin/ipfs
56
-COPY --from=builder $SRC_DIR/bin/container_daemon /usr/local/bin/start_ipfs
62
+COPY --from=builder --chmod=755 $SRC_DIR/bin/container_daemon /usr/local/bin/start_ipfs
63
COPY --from=builder $SRC_DIR/bin/container_init_run /usr/local/bin/container_init_run
64
59
-# Add suid bit on fusermount so it will run properly
65
+# Set SUID for fusermount to enable FUSE mounting by non-root user
66
RUN chmod 4755 /usr/local/bin/fusermount
67
62
-# Fix permissions on start_ipfs (ignore the build machine's permissions)
63
-RUN chmod 0755 /usr/local/bin/start_ipfs
64
-
65
-# Swarm TCP; should be exposed to the public
66
-EXPOSE 4001
67
-# Swarm UDP; should be exposed to the public
68
-EXPOSE 4001/udp
69
-# Daemon API; must not be exposed publicly but to client services under you control
68
+# Swarm P2P port (TCP/UDP) - expose publicly for peer connections
69
+EXPOSE 4001 4001/udp
70
+# API port - keep private, only for trusted clients
71
EXPOSE 5001
71
-# Web Gateway; can be exposed publicly with a proxy, e.g. as https://ipfs.example.org
72
+# Gateway port - can be exposed publicly via reverse proxy
73
EXPOSE 8080
73
-# Swarm Websockets; must be exposed publicly when the node is listening using the websocket transport (/ipX/.../tcp/8081/ws).
74
+# Swarm WebSockets - expose publicly for browser-based peers
75
EXPOSE 8081
76
76
-# Create the fs-repo directory and switch to a non-privileged user.
77
+# Create ipfs user (uid 1000) and required directories with proper ownership
78
ENV IPFS_PATH=/data/ipfs
78
-RUN mkdir -p $IPFS_PATH \
79
+RUN mkdir -p $IPFS_PATH /ipfs /ipns /mfs /container-init.d \
80
&& adduser -D -h $IPFS_PATH -u 1000 -G users ipfs \
80
- && chown ipfs:users $IPFS_PATH
81
-
82
-# Create mount points for `ipfs mount` command
83
-RUN mkdir /ipfs /ipns /mfs \
84
- && chown ipfs:users /ipfs /ipns /mfs
85
-
86
-# Create the init scripts directory
87
-RUN mkdir /container-init.d \
88
- && chown ipfs:users /container-init.d
81
+ && chown ipfs:users $IPFS_PATH /ipfs /ipns /mfs /container-init.d
82
90
-# Expose the fs-repo as a volume.
91
-# start_ipfs initializes an fs-repo if none is mounted.
92
-# Important this happens after the USER directive so permissions are correct.
83
+# Volume for IPFS repository data persistence
84
VOLUME $IPFS_PATH
85
86
# The default logging level
87
ENV GOLOG_LOG_LEVEL=""
88
98
-# This just makes sure that:
99
-# 1. There's an fs-repo, and initializes one if there isn't.
100
-# 2. The API and Gateway are accessible from outside the container.
89
+# Entrypoint initializes IPFS repo if needed and configures networking.
90
+# tini ensures proper signal handling and zombie process cleanup
91
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/start_ipfs"]
92
103
-# Healthcheck for the container
104
-# QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn is the CID of empty folder
93
+# Health check verifies IPFS daemon is responsive.
94
+# Uses empty directory CID (QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn) as test
95
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
96
CMD ipfs --api=/ip4/127.0.0.1/tcp/5001 dag stat /ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn || exit 1
97
108
-# Execute the daemon subcommand by default
98
+# Default: run IPFS daemon with auto-migration enabled
99
CMD ["daemon", "--migrate=true", "--agent-version-suffix=docker"]