5 changed files with 402 additions and 0 deletions
@ -0,0 +1,47 @@ |
|||||||
|
# Git files |
||||||
|
.git |
||||||
|
.gitignore |
||||||
|
.gitattributes |
||||||
|
|
||||||
|
# Build artifacts |
||||||
|
gitcitadel-online |
||||||
|
server |
||||||
|
*.exe |
||||||
|
*.dll |
||||||
|
*.so |
||||||
|
*.dylib |
||||||
|
|
||||||
|
# Test files |
||||||
|
*_test.go |
||||||
|
*.test |
||||||
|
|
||||||
|
# Documentation |
||||||
|
*.md |
||||||
|
!README.md |
||||||
|
LICENSE.md |
||||||
|
|
||||||
|
# IDE files |
||||||
|
.vscode |
||||||
|
.idea |
||||||
|
*.swp |
||||||
|
*.swo |
||||||
|
*~ |
||||||
|
|
||||||
|
# OS files |
||||||
|
.DS_Store |
||||||
|
Thumbs.db |
||||||
|
|
||||||
|
# Cache and temporary files |
||||||
|
cache/ |
||||||
|
*.log |
||||||
|
*.tmp |
||||||
|
|
||||||
|
# Node modules (will be installed in container) |
||||||
|
node_modules/ |
||||||
|
|
||||||
|
# Config file (should be mounted) |
||||||
|
config.yaml |
||||||
|
|
||||||
|
# Development files |
||||||
|
.env |
||||||
|
.env.local |
||||||
@ -0,0 +1,223 @@ |
|||||||
|
# Docker Setup for GitCitadel Online |
||||||
|
|
||||||
|
This guide explains how to run GitCitadel Online using Docker. |
||||||
|
|
||||||
|
## Prerequisites |
||||||
|
|
||||||
|
- Docker (version 20.10 or later) |
||||||
|
- Docker Compose (version 2.0 or later, optional but recommended) |
||||||
|
- Network access (for downloading dependencies and connecting to Nostr relays) |
||||||
|
|
||||||
|
## Image Details |
||||||
|
|
||||||
|
The Docker image uses **Alpine Linux** for a smaller footprint (~50MB base image vs ~200MB+ for Debian). This works well because: |
||||||
|
|
||||||
|
- The Go binary is statically compiled (`CGO_ENABLED=0`), so no C library dependencies |
||||||
|
- Node.js packages (`@asciidoctor/core`, `marked`) are pure JavaScript with no native bindings |
||||||
|
- Alpine's musl libc is sufficient for our use case |
||||||
|
|
||||||
|
If you encounter any compatibility issues, you can modify the Dockerfile to use Debian-based images (`golang:1.22` and `node:20-slim`), though this will increase the image size. |
||||||
|
|
||||||
|
## Quick Start |
||||||
|
|
||||||
|
### Using Docker Compose (Recommended) |
||||||
|
|
||||||
|
1. **Create your configuration file:** |
||||||
|
```bash |
||||||
|
cp config.yaml.example config.yaml |
||||||
|
# Edit config.yaml with your Nostr indices, relay URLs, and settings |
||||||
|
``` |
||||||
|
|
||||||
|
2. **Build and run:** |
||||||
|
```bash |
||||||
|
docker-compose up -d |
||||||
|
``` |
||||||
|
|
||||||
|
3. **View logs:** |
||||||
|
```bash |
||||||
|
docker-compose logs -f |
||||||
|
``` |
||||||
|
|
||||||
|
4. **Stop the container:** |
||||||
|
```bash |
||||||
|
docker-compose down |
||||||
|
``` |
||||||
|
|
||||||
|
### Using Docker directly |
||||||
|
|
||||||
|
1. **Build the image:** |
||||||
|
```bash |
||||||
|
docker build -t gitcitadel-online . |
||||||
|
``` |
||||||
|
|
||||||
|
2. **Create config file:** |
||||||
|
```bash |
||||||
|
cp config.yaml.example config.yaml |
||||||
|
# Edit config.yaml with your settings |
||||||
|
``` |
||||||
|
|
||||||
|
3. **Run the container:** |
||||||
|
```bash |
||||||
|
docker run -d \ |
||||||
|
--name gitcitadel-online \ |
||||||
|
-p 8080:8080 \ |
||||||
|
-v $(pwd)/config.yaml:/app/config.yaml:ro \ |
||||||
|
-v $(pwd)/cache:/app/cache \ |
||||||
|
--restart unless-stopped \ |
||||||
|
gitcitadel-online |
||||||
|
``` |
||||||
|
|
||||||
|
4. **View logs:** |
||||||
|
```bash |
||||||
|
docker logs -f gitcitadel-online |
||||||
|
``` |
||||||
|
|
||||||
|
5. **Stop the container:** |
||||||
|
```bash |
||||||
|
docker stop gitcitadel-online |
||||||
|
docker rm gitcitadel-online |
||||||
|
``` |
||||||
|
|
||||||
|
## Configuration |
||||||
|
|
||||||
|
### Config File |
||||||
|
|
||||||
|
The `config.yaml` file must be mounted into the container. The default path is `/app/config.yaml`. |
||||||
|
|
||||||
|
You can override the config path using the `--config` flag: |
||||||
|
```bash |
||||||
|
docker run ... gitcitadel-online --config /path/to/config.yaml |
||||||
|
``` |
||||||
|
|
||||||
|
### Port Mapping |
||||||
|
|
||||||
|
By default, the application runs on port 8080. You can change the host port mapping: |
||||||
|
```bash |
||||||
|
# Map to different host port |
||||||
|
docker run -p 3000:8080 ... |
||||||
|
``` |
||||||
|
|
||||||
|
Or update `docker-compose.yml`: |
||||||
|
```yaml |
||||||
|
ports: |
||||||
|
- "3000:8080" |
||||||
|
``` |
||||||
|
|
||||||
|
### Cache Persistence |
||||||
|
|
||||||
|
The cache directory (`cache/`) is persisted as a volume to maintain cached pages and media between container restarts. |
||||||
|
|
||||||
|
### Environment Variables |
||||||
|
|
||||||
|
You can pass environment variables, though most configuration should be in `config.yaml`: |
||||||
|
|
||||||
|
```bash |
||||||
|
docker run -e LOG_LEVEL=debug ... |
||||||
|
``` |
||||||
|
|
||||||
|
## Development Mode |
||||||
|
|
||||||
|
To run in development mode with verbose logging: |
||||||
|
|
||||||
|
```bash |
||||||
|
docker run ... gitcitadel-online --dev |
||||||
|
``` |
||||||
|
|
||||||
|
Or with docker-compose, override the command: |
||||||
|
```yaml |
||||||
|
command: ["--config", "/app/config.yaml", "--dev"] |
||||||
|
``` |
||||||
|
|
||||||
|
## Health Check |
||||||
|
|
||||||
|
The container includes a health check that monitors the `/health` endpoint. You can check the health status: |
||||||
|
|
||||||
|
```bash |
||||||
|
docker ps |
||||||
|
# Look for "healthy" status |
||||||
|
|
||||||
|
# Or inspect directly |
||||||
|
docker inspect --format='{{.State.Health.Status}}' gitcitadel-online |
||||||
|
``` |
||||||
|
|
||||||
|
## Troubleshooting |
||||||
|
|
||||||
|
### Container won't start |
||||||
|
|
||||||
|
1. **Check logs:** |
||||||
|
```bash |
||||||
|
docker logs gitcitadel-online |
||||||
|
``` |
||||||
|
|
||||||
|
2. **Verify config file:** |
||||||
|
```bash |
||||||
|
docker exec gitcitadel-online cat /app/config.yaml |
||||||
|
``` |
||||||
|
|
||||||
|
3. **Check file permissions:** |
||||||
|
The container runs as a non-root user (UID 1000). Ensure cache directory is writable: |
||||||
|
```bash |
||||||
|
chmod -R 777 cache/ |
||||||
|
``` |
||||||
|
|
||||||
|
### Can't connect to Nostr relays |
||||||
|
|
||||||
|
- Ensure the container has network access |
||||||
|
- Check firewall rules if running on a remote server |
||||||
|
- Verify relay URLs in `config.yaml` are correct |
||||||
|
|
||||||
|
### Cache not persisting |
||||||
|
|
||||||
|
- Ensure the cache volume is properly mounted |
||||||
|
- Check volume permissions |
||||||
|
- Verify the cache directory exists and is writable |
||||||
|
|
||||||
|
## Building for Different Architectures |
||||||
|
|
||||||
|
The Dockerfile builds for `linux/amd64` by default. To build for other architectures: |
||||||
|
|
||||||
|
```bash |
||||||
|
# For ARM64 (e.g., Raspberry Pi, Apple Silicon) |
||||||
|
docker buildx build --platform linux/arm64 -t gitcitadel-online . |
||||||
|
|
||||||
|
# For multiple architectures |
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 -t gitcitadel-online . |
||||||
|
``` |
||||||
|
|
||||||
|
## Production Deployment |
||||||
|
|
||||||
|
For production deployment: |
||||||
|
|
||||||
|
1. **Use a reverse proxy** (nginx, Traefik, etc.) in front of the container |
||||||
|
2. **Set up SSL/TLS** certificates |
||||||
|
3. **Configure proper logging** and monitoring |
||||||
|
4. **Use secrets management** for sensitive configuration |
||||||
|
5. **Set resource limits** in docker-compose.yml: |
||||||
|
```yaml |
||||||
|
deploy: |
||||||
|
resources: |
||||||
|
limits: |
||||||
|
cpus: '1' |
||||||
|
memory: 512M |
||||||
|
``` |
||||||
|
|
||||||
|
## Updating |
||||||
|
|
||||||
|
To update to a new version: |
||||||
|
|
||||||
|
```bash |
||||||
|
# Pull latest code |
||||||
|
git pull |
||||||
|
|
||||||
|
# Rebuild and restart |
||||||
|
docker-compose build |
||||||
|
docker-compose up -d |
||||||
|
``` |
||||||
|
|
||||||
|
Or with Docker directly: |
||||||
|
```bash |
||||||
|
docker build -t gitcitadel-online . |
||||||
|
docker stop gitcitadel-online |
||||||
|
docker rm gitcitadel-online |
||||||
|
docker run ... # (same command as before) |
||||||
|
``` |
||||||
@ -0,0 +1,77 @@ |
|||||||
|
# Multi-stage build for GitCitadel Online |
||||||
|
# Using Alpine Linux for smaller image size (~50MB vs ~200MB+ for Debian) |
||||||
|
# Alpine works well here because: |
||||||
|
# - Go binary is statically compiled (CGO_ENABLED=0) |
||||||
|
# - Node.js packages are pure JavaScript (no native bindings) |
||||||
|
# - No C library dependencies required |
||||||
|
|
||||||
|
# Stage 1: Build Go application |
||||||
|
FROM golang:1.22-alpine AS builder |
||||||
|
|
||||||
|
# Install build dependencies |
||||||
|
RUN apk add --no-cache git |
||||||
|
|
||||||
|
# Set working directory |
||||||
|
WORKDIR /build |
||||||
|
|
||||||
|
# Copy go mod files |
||||||
|
COPY go.mod go.sum ./ |
||||||
|
RUN go mod download |
||||||
|
|
||||||
|
# Copy source code |
||||||
|
COPY . . |
||||||
|
|
||||||
|
# Build the application |
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags='-w -s' -o gitcitadel-online ./cmd/server |
||||||
|
|
||||||
|
# Stage 2: Runtime with Node.js for AsciiDoc processing |
||||||
|
FROM node:20-alpine |
||||||
|
|
||||||
|
# Install runtime dependencies (wget for health check and nostr-tools download) |
||||||
|
RUN apk add --no-cache ca-certificates tzdata wget |
||||||
|
|
||||||
|
# Set working directory |
||||||
|
WORKDIR /app |
||||||
|
|
||||||
|
# Install Node.js dependencies for AsciiDoc processing |
||||||
|
COPY package.json package-lock.json ./ |
||||||
|
RUN npm ci --only=production |
||||||
|
|
||||||
|
# Copy built binary from builder |
||||||
|
COPY --from=builder /build/gitcitadel-online /app/gitcitadel-online |
||||||
|
|
||||||
|
# Copy static files and templates |
||||||
|
COPY static/ ./static/ |
||||||
|
COPY templates/ ./templates/ |
||||||
|
|
||||||
|
# Download nostr-tools bundle if not present (for contact form) |
||||||
|
RUN if [ ! -f ./static/js/nostr.bundle.js ]; then \ |
||||||
|
mkdir -p ./static/js && \ |
||||||
|
wget -O ./static/js/nostr.bundle.js https://unpkg.com/nostr-tools@latest/lib/nostr.bundle.js || \ |
||||||
|
echo "Warning: Failed to download nostr-tools bundle"; \ |
||||||
|
fi |
||||||
|
|
||||||
|
# Copy example config (user should mount their own config.yaml) |
||||||
|
COPY config.yaml.example ./config.yaml.example |
||||||
|
|
||||||
|
# Create cache directories |
||||||
|
RUN mkdir -p cache/media |
||||||
|
|
||||||
|
# Create non-root user for security |
||||||
|
RUN addgroup -g 1000 appuser && \ |
||||||
|
adduser -D -u 1000 -G appuser appuser && \ |
||||||
|
chown -R appuser:appuser /app |
||||||
|
|
||||||
|
# Switch to non-root user |
||||||
|
USER appuser |
||||||
|
|
||||||
|
# Expose port (default 8080, can be overridden via config) |
||||||
|
EXPOSE 8080 |
||||||
|
|
||||||
|
# Health check |
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ |
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1 |
||||||
|
|
||||||
|
# Run the application |
||||||
|
ENTRYPOINT ["/app/gitcitadel-online"] |
||||||
|
CMD ["--config", "/app/config.yaml"] |
||||||
@ -0,0 +1,33 @@ |
|||||||
|
version: '3.8' |
||||||
|
|
||||||
|
services: |
||||||
|
gitcitadel-online: |
||||||
|
build: |
||||||
|
context: . |
||||||
|
dockerfile: Dockerfile |
||||||
|
container_name: gitcitadel-online |
||||||
|
restart: unless-stopped |
||||||
|
ports: |
||||||
|
- "8080:8080" |
||||||
|
volumes: |
||||||
|
# Mount config file (create from config.yaml.example) |
||||||
|
- ./config.yaml:/app/config.yaml:ro |
||||||
|
# Persist cache directory |
||||||
|
- ./cache:/app/cache |
||||||
|
environment: |
||||||
|
# Optional: override config path |
||||||
|
# - CONFIG_PATH=/app/config.yaml |
||||||
|
# Optional: set log level |
||||||
|
# - LOG_LEVEL=info |
||||||
|
networks: |
||||||
|
- gitcitadel-network |
||||||
|
healthcheck: |
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"] |
||||||
|
interval: 30s |
||||||
|
timeout: 10s |
||||||
|
retries: 3 |
||||||
|
start_period: 40s |
||||||
|
|
||||||
|
networks: |
||||||
|
gitcitadel-network: |
||||||
|
driver: bridge |
||||||
Loading…
Reference in new issue