Initial commit: Claude Dev Container with Java multi-version, Docker CLI, and web terminal

This commit is contained in:
openclaw
2026-02-24 16:58:17 +00:00
commit a84835cd7e
10 changed files with 732 additions and 0 deletions

5
.env.example Normal file
View File

@@ -0,0 +1,5 @@
# Copy this file to .env and set your own passwords
# Web terminal credentials
TERMINAL_USER=developer
TERMINAL_PASSWORD=changeme

12
.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
# Environment variables (contains passwords!)
.env
# Claude credentials (personal/sensitive)
claude-credentials/
# Persistent data folders
workspace/
# Docker
.DS_Store
*.log

104
Dockerfile Normal file
View File

@@ -0,0 +1,104 @@
FROM ubuntu:22.04
# Prevent interactive prompts during installation
ENV DEBIAN_FRONTEND=noninteractive
# Set up user and workspace
ENV USER=developer
ENV HOME=/home/$USER
ENV WORKSPACE=$HOME/workspace
ENV SDKMAN_DIR=$HOME/.sdkman
# Install base dependencies
RUN apt-get update && apt-get install -y \
curl \
wget \
git \
build-essential \
zip \
unzip \
software-properties-common \
ca-certificates \
gnupg \
lsb-release \
sudo \
nano \
vim \
htop \
net-tools \
&& rm -rf /var/lib/apt/lists/*
# Create developer user with sudo privileges
RUN useradd -m -s /bin/bash -G sudo $USER && \
echo "$USER ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
mkdir -p $WORKSPACE && \
chown -R $USER:$USER $HOME
# Switch to developer user
USER $USER
WORKDIR $HOME
# Install SDKMAN
RUN curl -s "https://get.sdkman.io" | bash
# Install multiple Java versions via SDKMAN
RUN bash -c "source $SDKMAN_DIR/bin/sdkman-init.sh && \
sdk install java 11.0.22-tem && \
sdk install java 17.0.10-tem && \
sdk install java 21.0.2-tem && \
sdk install java 25-tem && \
sdk default java 25-tem"
# Install Maven and Gradle
RUN bash -c "source $SDKMAN_DIR/bin/sdkman-init.sh && \
sdk install maven && \
sdk install gradle"
# Switch back to root for system-level installations
USER root
# Install Docker CLI (no daemon - will use host socket)
RUN install -m 0755 -d /etc/apt/keyrings && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
chmod a+r /etc/apt/keyrings/docker.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && \
apt-get install -y docker-ce-cli docker-compose-plugin && \
usermod -aG docker $USER && \
rm -rf /var/lib/apt/lists/*
# Install ttyd (web terminal)
RUN wget https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.x86_64 -O /usr/local/bin/ttyd && \
chmod +x /usr/local/bin/ttyd
# Install Node.js (needed for Claude Code CLI)
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*
# Switch back to developer user
USER $USER
# Install Claude Code CLI
RUN npm install -g @anthropic-ai/claude-code
# Create .claude directory (will be mounted with credentials from Mac)
RUN mkdir -p $HOME/.claude
# Source SDKMAN in bashrc for interactive shells
RUN echo 'source "$SDKMAN_DIR/bin/sdkman-init.sh"' >> $HOME/.bashrc
# Create startup script
USER root
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Expose ports
# 7681: ttyd (web terminal)
EXPOSE 7681
USER $USER
WORKDIR $WORKSPACE
ENTRYPOINT ["/entrypoint.sh"]

40
Makefile Normal file
View File

@@ -0,0 +1,40 @@
.PHONY: help build up down restart logs shell clean
help:
@echo "Claude Dev Container - Commands"
@echo ""
@echo " make build - Build the Docker image"
@echo " make up - Start the container"
@echo " make down - Stop the container"
@echo " make restart - Restart the container"
@echo " make logs - Show container logs"
@echo " make shell - Open bash shell in container"
@echo " make clean - Remove container and image"
@echo ""
build:
docker compose build
up:
docker compose up -d
@echo ""
@echo "Container started!"
@echo " VS Code: http://localhost:8080"
@echo " Web Terminal: http://localhost:7681"
@echo ""
down:
docker compose down
restart:
docker compose restart
logs:
docker compose logs -f
shell:
docker exec -it claude-dev-container bash
clean:
docker compose down
docker rmi claude-dev-container-claude-dev || true

150
QUICKSTART.md Normal file
View File

@@ -0,0 +1,150 @@
# 🚀 Quick Start
## Voorbereiding (BELANGRIJK!)
### 1. Kopieer Claude credentials van Mac
**Op je Mac** (waar je al ingelogd bent in Claude Code):
```bash
# Check of credentials bestaan
ls -la ~/.claude
# Kopieer naar NAS
scp -r ~/.claude/ admin@[nas-ip]:/docker/claude-dev/claude-credentials
```
**Of via Finder**: Cmd+Shift+G → `~/.claude` → Upload naar NAS
---
## Voor Synology
### 2. Upload naar Synology
Upload deze hele folder naar: `/docker/claude-dev`
### 3. Check Docker group ID
```bash
ssh admin@[nas-ip]
getent group docker
# Output: docker:x:999:...
```
### 4. Pas docker-compose.yml aan (als nodig)
```yaml
group_add:
- "999" # <- Zet hier het juiste nummer uit stap 3
```
### 5. Zet wachtwoorden
```bash
cd /docker/claude-dev
cp .env.example .env
nano .env # Pas TERMINAL_PASSWORD aan
```
### 6. Start via Container Manager
- Open Container Manager
- Project → Create
- Selecteer `/docker/claude-dev`
- Start!
### 7. Open terminal
Browser → `http://[synology-ip]:7681`
Login met credentials uit `.env`
---
## Lokaal testen (Mac/Linux)
```bash
# Check setup
./check-setup.sh
# Kopieer je eigen credentials
cp -r ~/.claude ./claude-credentials
# Setup credentials
cp .env.example .env
nano .env
# Build en start
make build && make up
# Of zonder Makefile:
docker compose build
docker compose up -d
# Open terminal
open http://localhost:7681
```
---
## Eerste keer in de container
```bash
# Check of Claude werkt
claude --version
# Test authentication
claude "Hello, can you help me?"
# Check Java versies
sdk list java
# Test Docker toegang
docker ps
# Start coding!
claude chat
```
## Claude Code commando's
```bash
# Interactive chat
claude chat
# One-shot
claude "Maak een Spring Boot REST API"
# Met context
claude --context pom.xml src/ "add JUnit tests"
# Model kiezen
claude -m claude-opus-4 "complex vraag"
```
## Java versie switchen
```bash
# Tijdelijk (deze sessie)
sdk use java 17.0.10-tem
# Permanent
sdk default java 21.0.2-tem
```
---
## Troubleshooting
**Claude zegt "not authenticated"**:
```bash
# Check credentials
ls -la ~/.claude
# Als leeg: opnieuw kopiëren van Mac
```
**Terminal vraagt om login maar credentials werken niet**:
- Check `.env` bestand
- Restart container: `docker compose restart`
**Docker permission denied**:
- Check `group_add` in docker-compose.yml
- Moet matchen met output van `getent group docker`
---
**Klaar! 🎉** Open `http://[ip]:7681` en begin met `claude chat`

239
README.md Normal file
View File

@@ -0,0 +1,239 @@
# Claude Dev Container
Docker container met Java development environment, Claude Code CLI, web terminal en Docker CLI.
## Features
- 🔢 **Multiple Java versions** (11, 17, 21, 25) via SDKMAN - makkelijk switchen
- 🤖 **Claude Code CLI** - AI coding assistant in de terminal
- 🖥️ **Web terminal** (ttyd) met basic authentication
- 🐳 **Docker CLI** - gebruikt host Docker socket (Synology compatible)
- 📦 **Maven & Gradle** pre-installed
- 🔐 **Password protected** terminal
## Installatie op Synology
### 1. Claude credentials voorbereiden (BELANGRIJK!)
**Op je Mac** waar je al ingelogd bent in Claude Code:
```bash
# Check of credentials bestaan
ls -la ~/.claude
# Kopieer naar NAS (pas IP aan)
scp -r ~/.claude/ admin@[nas-ip]:/docker/claude-dev/claude-credentials
```
**Of via Finder:**
1. Cmd+Shift+G → typ `~/.claude`
2. Kopieer de hele folder
3. Upload naar NAS via File Station → `/docker/claude-dev/claude-credentials`
### 2. Bestanden voorbereiden
Upload deze folder naar je Synology (bijv. via File Station naar `/docker/claude-dev`).
**Structuur moet zijn:**
```
/docker/claude-dev/
├── claude-credentials/ # Gekopieërd van Mac ~/.claude
│ └── session.json # (en andere bestanden)
├── Dockerfile
├── docker-compose.yml
├── entrypoint.sh
└── ...
```
### 3. Wachtwoorden instellen
```bash
cd /docker/claude-dev
cp .env.example .env
nano .env # Pas terminal wachtwoord aan
```
### 4. Docker group ID checken (belangrijk!)
SSH naar je Synology en check de Docker group ID:
```bash
getent group docker
```
Je ziet iets als: `docker:x:999:...`
Als het getal **niet** 999 is, pas het aan in `docker-compose.yml` bij `group_add`.
### 5. Container starten
Via **Container Manager**:
1. Open Container Manager
2. Ga naar Project
3. Klik "Create"
4. Selecteer de folder met `docker-compose.yml`
5. Start het project
**Of via SSH:**
```bash
cd /docker/claude-dev
docker compose up -d
```
### 6. Toegang
**Web Terminal**: `http://[synology-ip]:7681`
- Login: gebruik `TERMINAL_USER` en `TERMINAL_PASSWORD` uit `.env`
## Claude Code gebruiken
In de terminal:
```bash
# Interactive chat
claude chat
# One-shot commando
claude "Maak een Spring Boot REST API"
# Met opties
claude -p "Schrijf unit tests" --model claude-opus-4
# Hulp
claude --help
```
Claude gebruikt automatisch je gemounte credentials uit `~/.claude`.
## Java versies switchen
```bash
# Lijst van geïnstalleerde versies
sdk list java
# Switch voor huidige sessie
sdk use java 17.0.10-tem
# Zet als default
sdk default java 21.0.2-tem
# Check huidige versie
java -version
```
## Docker gebruiken
De container gebruikt de Docker socket van je Synology host:
```bash
# Werkt gewoon
docker ps
docker images
docker run hello-world
docker compose up
```
## Workspace persistentie
Je code wordt opgeslagen in: `./workspace/`
Deze map is gemount, dus je werk blijft bewaard na container restart.
## Troubleshooting
### Claude Code zegt "not authenticated"
Check of credentials correct gemount zijn:
```bash
# In de container
ls -la ~/.claude
cat ~/.claude/session.json
```
Als de folder leeg is:
1. Kopieer opnieuw vanaf Mac: `scp -r ~/.claude admin@[nas]:/docker/claude-dev/claude-credentials`
2. Check permissions: `chmod -R 755 ./claude-credentials`
3. Restart container
### Docker permission denied
Check of de `group_add` in `docker-compose.yml` matcht met je Docker group ID:
```bash
getent group docker
```
### Container start niet
Check logs:
```bash
docker logs claude-dev-container
```
Of via Container Manager: selecteer container → Details → Log
### Poort in gebruik
Pas de poort aan in `docker-compose.yml`:
```yaml
ports:
- "7682:7681" # bijv. 7682 in plaats van 7681
```
## Structuur
```
claude-dev-container/
├── Dockerfile # Container definitie
├── docker-compose.yml # Synology deployment
├── entrypoint.sh # Startup script
├── .env # Wachtwoorden (niet committen!)
├── .env.example # Template voor .env
├── claude-credentials/ # Gekopieërd van Mac ~/.claude (niet committen!)
├── workspace/ # Je code (persistent)
└── README.md # Deze file
```
## Custom aanpassingen
### Meer Java versies toevoegen
Edit `Dockerfile`, voeg toe in de SDKMAN sectie:
```dockerfile
sdk install java 23-tem && \
```
### Extra tools installeren
In de `Dockerfile`, voeg toe bij apt-get install of maak een nieuwe RUN statement.
### Memory limits instellen
In `docker-compose.yml`:
```yaml
deploy:
resources:
limits:
memory: 4G
```
## Claude Code CLI opties
```bash
# Model kiezen
claude -m claude-opus-4 "vraag"
claude -m claude-sonnet-4 "vraag"
# Context toevoegen
claude --context file1.java file2.java "refactor deze code"
# Headless mode (non-interactive output)
claude -p "genereer code"
# Working directory
claude --cwd /path/to/project "maak tests"
```
Zie volledige documentatie: https://code.claude.com/docs
---
Veel plezier met coderen! 🚀

49
check-setup.sh Normal file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
echo "🔍 Claude Dev Container - Setup Check"
echo "======================================"
echo ""
# Check if .env exists
if [ -f .env ]; then
echo "✅ .env file exists"
else
echo "❌ .env file missing - copy from .env.example"
echo " Run: cp .env.example .env"
fi
# Check Docker socket
if [ -e /var/run/docker.sock ]; then
echo "✅ Docker socket found"
DOCKER_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || stat -f '%g' /var/run/docker.sock)
echo " Docker group ID: $DOCKER_GID"
echo ""
echo " ⚠️ Make sure docker-compose.yml has 'group_add: [\"$DOCKER_GID\"]'"
else
echo "⚠️ Docker socket not found at /var/run/docker.sock"
echo " This is normal if you're not on the Synology host"
fi
# Check Docker
if command -v docker &> /dev/null; then
echo "✅ Docker installed"
docker --version
else
echo "❌ Docker not found"
fi
# Check Docker Compose
if docker compose version &> /dev/null; then
echo "✅ Docker Compose available"
docker compose version
elif command -v docker-compose &> /dev/null; then
echo "✅ Docker Compose available (standalone)"
docker-compose --version
else
echo "❌ Docker Compose not found"
fi
echo ""
echo "======================================"
echo "Ready to build? Run: make build && make up"
echo "Or: docker compose build && docker compose up -d"

32
docker-compose.yml Normal file
View File

@@ -0,0 +1,32 @@
version: '3.8'
services:
claude-dev:
build: .
container_name: claude-dev-container
restart: unless-stopped
ports:
- "7681:7681" # ttyd (web terminal)
environment:
# Set custom terminal credentials via .env file
- TERMINAL_USER=${TERMINAL_USER:-developer}
- TERMINAL_PASSWORD=${TERMINAL_PASSWORD:-changeme}
volumes:
# Mount host Docker socket (for Synology)
- /var/run/docker.sock:/var/run/docker.sock
# Persistent workspace
- /volume1/docker/claude-dev/workspace:/home/developer/workspace
# Claude Code credentials (copy from Mac ~/.claude)
- /volume1/docker/claude-dev/claude-config:/home/developer/.claude
# Run as developer user
user: "1000:1000"
# Give access to docker group (typically GID 999 on Synology, adjust if needed)
group_add:
- "999" # Docker group - check with: getent group docker on your Synology

47
entrypoint.sh Normal file
View File

@@ -0,0 +1,47 @@
#!/bin/bash
# Source SDKMAN for Java commands
source "$SDKMAN_DIR/bin/sdkman-init.sh"
# Display startup info
echo "==================================="
echo "Claude Dev Container Starting..."
echo "==================================="
echo "Available Java versions:"
sdk list java | grep installed
echo ""
echo "Current Java version:"
java -version
echo ""
echo "Claude Code CLI: $(claude --version 2>/dev/null || echo 'installed')"
echo ""
echo "==================================="
echo "Services:"
echo " - Web terminal: http://localhost:7681"
echo "==================================="
echo ""
echo "Quick start:"
echo " claude chat # Start interactive chat"
echo " claude 'your prompt' # One-shot command"
echo " sdk list java # Show Java versions"
echo " sdk use java 17 # Switch Java version"
echo " docker ps # Docker commands work!"
echo ""
echo "==================================="
# Get credentials from environment variables or use defaults
TERMINAL_USER=${TERMINAL_USER:-developer}
TERMINAL_PASSWORD=${TERMINAL_PASSWORD:-changeme}
# Check if Claude credentials exist
if [ -f "$HOME/.claude/session.json" ]; then
echo "✅ Claude Code credentials found - ready to use!"
else
echo "⚠️ No Claude credentials found"
echo " Copy ~/.claude from your Mac to ./claude-credentials/"
fi
echo ""
# Start ttyd with basic auth
echo "Starting web terminal on port 7681..."
exec ttyd -p 7681 -c $TERMINAL_USER:$TERMINAL_PASSWORD bash

54
setup-credentials.sh Normal file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
echo "🔐 Claude Credentials Setup"
echo "============================"
echo ""
# Check if running on Mac
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "✅ Running on Mac"
# Check if ~/.claude exists
if [ -d "$HOME/.claude" ]; then
echo "✅ Found Claude credentials at ~/.claude"
# Create target directory
mkdir -p ./claude-credentials
# Copy credentials
echo ""
echo "Copying credentials..."
cp -r "$HOME/.claude/"* ./claude-credentials/ 2>/dev/null
if [ $? -eq 0 ]; then
echo "✅ Credentials copied to ./claude-credentials/"
echo ""
echo "Next steps:"
echo "1. If deploying to Synology, upload this folder"
echo "2. Or build and run locally: make build && make up"
else
echo "❌ Failed to copy credentials"
exit 1
fi
else
echo "❌ No Claude credentials found at ~/.claude"
echo ""
echo "Please login to Claude Code first:"
echo " 1. Install Claude Code CLI: npm install -g @anthropic-ai/claude-code"
echo " 2. Run: claude"
echo " 3. Complete the login flow"
echo " 4. Run this script again"
exit 1
fi
else
echo " Not running on Mac"
echo ""
echo "To copy credentials from your Mac:"
echo ""
echo " scp -r ~/.claude/ user@this-machine:$(pwd)/claude-credentials"
echo ""
echo "Or manually copy the ~/.claude folder from your Mac"
fi
echo ""
echo "============================"