Tips & Troubleshooting
Dev server port forwarding
If you run a dev server inside the container (e.g., npm run dev on port 5173), forward it to your local machine:
ssh -L 5173:localhost:5173 -p 3434 abc@<server-ip>
Then open http://localhost:5173 in your browser. Repeat for each port you need. The forwarded port stays alive as long as the SSH session is open.
Keeping Claude Code up to date
Claude Code updates frequently. To update inside the container:
docker exec -it dev-desktop bash
su - abc
source ~/.nvm/nvm.sh
npm update -g @anthropic-ai/claude-code
The update persists in /config/.npm-global, no need to redo it after rebuilds.
Docker-in-Docker permissions
The docker.sock mount gives the container root access to the host's Docker daemon. The abc user inside the container may need to be in the docker group to use it without sudo. If you get permission errors:
docker exec -it dev-desktop bash
sudo usermod -aG docker abc
# Then restart the container
You may also need to match the host's docker GID inside the container.
SSH login issues
Wrong password? Use SUDO_PASSWORD
SSH uses SUDO_PASSWORD, not PASSWORD. The web desktop uses PASSWORD for KasmVNC login. These are two different variables in the compose file.
ssh -p 3434 abc@<server-ip>
# Password: whatever you set as SUDO_PASSWORD
Permission denied even with correct password
First, check the init logs to see if the password was set:
docker logs dev-desktop 2>&1 | grep -i "ssh\|password\|chpasswd"
Look for:
SSH password set for abc→ password was set, issue is elsewhereWARNING: SUDO_PASSWORD is empty→ env var not reaching the container, check compose.yamlWARNING: SUDO_PASSWORD is still the placeholder→ you forgot to replaceCHANGE_ME_SUDO_PASSWORDERROR: chpasswd failed→ user might not exist yet, checkcat /etc/passwd
Also verify SSH is running:
docker exec -it dev-desktop service ssh status
If it's not running, start it:
docker exec -it -u root dev-desktop service ssh start
Multiple projects
The rsync cmd hardcodes the project path. For multiple projects, create separate .code-workspace files, one per project. Each contains its own emeraldwalk.runonsave command with the correct server path.
Known edge cases
rsync timing
If you edit a file and immediately run a command on the server that reads it, the server might still have the old version if you haven't clicked away yet. Click away from the editor first, or save manually (Ctrl+S / Cmd+S) to force an rsync.
rsync needs passwordless SSH
The Run on Save rsync command runs in the background and cannot prompt for a password. You need one of:
- SSH keys: set up key based authentication so rsync connects without a password
- SSH multiplexing: if you added the optional ControlMaster config, run
ssh -p 3434 abc@<server-ip>once from a terminal to open the shared connection; rsync then rides it without prompting
Setting up your GitHub token
The stack uses GITHUB_TOKEN to authenticate git operations (clone, push, pull) against private repos. It's set in compose.yaml and applied automatically by the init script via git config --global url.insteadOf.
Creating a fine grained token (recommended)
- Go to github.com/settings/tokens?type=beta
- Click Generate new token
- Fill in:
- Token name: e.g.
cloud-dev-stack - Resource owner: your user or org
- Repository access: choose All repositories or pick the specific repos you need
- Token name: e.g.
- Under Permissions → Repository permissions, set:
- Contents: Read and write (required for clone, push, pull)
- Metadata: Read-only (auto selected, required for all tokens)
- Click Generate token and copy it
Creating a classic token (alternative)
- Go to github.com/settings/tokens
- Click Generate new token → Generate new token (classic)
- Give it a name and check:
- repo: full control of private repositories (or just
public_repoif you only work with public repos)
- repo: full control of private repositories (or just
- Click Generate token and copy it
Using the token
Paste the token into your compose file:
# compose.yaml (or compose-casaos.yaml)
environment:
GITHUB_TOKEN: github_pat_xxxxxxxxxxxx # replace CHANGE_ME_GITHUB_TOKEN
Then recreate the container:
docker compose up -d --force-recreate
Verifying it works
SSH into the container and check that git uses the token:
ssh -p 3434 abc@<server-ip>
git config --global url.'https://oauth2:'.insteadOf
# Should print: https://github.com/
Then test with a private repo:
git ls-remote https://github.com/you/private-repo.git
# Should succeed without prompting for a password
Token security
- The token is stored inside the container's git config: it persists across rebuilds because
/config/.gitconfiglives on the shared volume - Treat your compose file as a secret: anyone with the token can act as you on GitHub
- If the token is ever leaked, revoke it immediately at github.com/settings/tokens
See also
- Environment Variables: full reference for all configurable env vars (API keys, Git, models)
- Daily Workflow: tmux, persistent sessions, Termius setup