Root cause: the `git` service user's UID is assigned dynamically (random, non-persistent across container recreations), and __fix_permissions re-chowns APPLICATION_DIRS on every startup to whatever UID `git` currently has. However DATABASE_DIR / DATABASE_BASE_DIR (e.g. /data/db/sqlite for the sqlite backend) live under /data/db, outside APPLICATION_DIRS ($ETC_DIR $CONF_DIR $DATA_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR, where DATA_DIR is /data/opengist, not /data). So whenever the on-disk DB ownership didn't already match the current `git` UID, it was never corrected, and opengist failed every start with "attempt to write a readonly database (8)", causing the container to exit and get restarted indefinitely. Reproduced against a live instance (git.casjay.work, casjaysdevdocker/opengist:latest): confirmed via container logs and `id git` vs `ls -la /data/db/sqlite` that the sqlite file's owning UID did not match the current `git` UID, and manually chowning it fixed that boot but the mismatch could recur on any future UID reassignment. Reproduced locally by pre-seeding a volume with the DB owned by an arbitrary UID (9999) and confirming, pre-fix, __fix_permissions never touched it; post-fix, the container's first boot re-chowns it to the newly assigned `git` UID and opengist starts cleanly. - rootfs/usr/local/etc/docker/init.d/00-opengist.sh: after the database-type case block resolves DATABASE_DIR/DATABASE_BASE_DIR, append both to ADD_APPLICATION_DIRS so __fix_permissions picks them up on every startup, regardless of database backend
opengist
A containerized OpenGist — a self-hosted pastebin powered by Git. Create, share, and fork code snippets with full Git history, HTTP clone, SSH push/pull, and OAuth2 login via GitHub, GitLab, Gitea, or OpenID Connect. Built on Alpine Linux with SQLite storage and no external database required.
📦 Install
Via dockermgr (recommended)
sudo bash -c "$(curl -q -LSsf "https://github.com/systemmgr/installer/raw/main/install.sh")"
sudo systemmgr --config && sudo systemmgr install scripts
dockermgr update opengist
Manual docker run
docker run -d \
--restart always \
--name casjaysdevdocker-opengist-latest \
--hostname opengist \
-e TZ=${TIMEZONE:-America/New_York} \
-v /srv/$USER/docker/casjaysdevdocker/opengist/latest/volumes/data:/data:z \
-v /srv/$USER/docker/casjaysdevdocker/opengist/latest/volumes/config:/config:z \
-p 172.17.0.1:80:80 \
-p 172.17.0.1:7823:7823 \
casjaysdevdocker/opengist:latest
docker-compose
services:
opengist:
image: casjaysdevdocker/opengist:latest
container_name: casjaysdevdocker-opengist
hostname: opengist
environment:
- TZ=America/New_York
volumes:
- "/srv/$USER/docker/casjaysdevdocker/opengist/latest/volumes/data:/data:z"
- "/srv/$USER/docker/casjaysdevdocker/opengist/latest/volumes/config:/config:z"
ports:
- "172.17.0.1:80:80"
- "172.17.0.1:7823:7823"
restart: always
⚙️ Configuration
Volumes
| Path | Purpose |
|---|---|
/config |
Runtime configuration (auto-generated on first start) |
/data |
Gist repositories, SQLite database, logs, and index |
Ports
| Port | Protocol | Purpose |
|---|---|---|
80 |
HTTP | Web UI and HTTP Git clone/pull |
7823 |
TCP | Built-in SSH server for Git push/pull |
Environment variables
| Variable | Default | Description |
|---|---|---|
TZ |
America/New_York |
Container timezone |
HOSTNAME |
casjaysdev-opengist |
Sets the external-url in opengist config |
SERVER_NAME / FULL_DOMAIN_NAME |
— | Override hostname for external URL |
OPENGIST_APPNAME_ENABLED |
yes |
Set to no to disable the service |
OPENGIST_ROOT_USER_NAME |
— | Initial admin username |
OPENGIST_ROOT_PASS_WORD |
— | Initial admin password |
OPENGIST_USER_NAME |
— | Initial normal user name |
OPENGIST_USER_PASS_WORD |
— | Initial normal user password |
DEBUGGER |
— | Set to on to enable shell-level debug tracing |
Runtime config overrides
Place a shell script at /config/env/opengist.sh inside the container (or mount it as a file) to override any variable at runtime without rebuilding the image. A template is written on first start.
OAuth2
After first start, edit /config/opengist/config.yaml to add OAuth2 credentials:
github.client-key: <your-key>
github.secret: <your-secret>
gitlab.client-key: <your-key>
gitlab.secret: <your-secret>
gitlab.url: https://gitlab.com/
gitea.client-key: <your-key>
gitea.secret: <your-secret>
gitea.url: https://your-gitea-instance/
oidc.client-key: <your-key>
oidc.secret: <your-secret>
oidc.discovery-url: https://auth.example.com/.well-known/openid-configuration
OAuth2 callback URLs must follow the pattern:
http://<opengist-url>/oauth/<github|gitlab|gitea|openid-connect>/callback
🛠️ Development
Prerequisites
- Docker with
buildxsupport git
Get source
git clone "https://github.com/casjaysdevdocker/opengist" \
"$HOME/Projects/github/casjaysdevdocker/opengist"
cd "$HOME/Projects/github/casjaysdevdocker/opengist"
Or via dockermgr:
dockermgr download src casjaysdevdocker/opengist
Build the image
buildx
The build downloads the latest OpenGist release binary from GitHub at build time and bundles it into the image.
📄 License
WTFPL — see LICENSE.md