Claude-skill-registry configure-ubuntu
Ubuntu server configuration via cloud-init and systemd. Use when writing cloud-init YAML, configuring systemd services, setting up nginx, or troubleshooting VM configuration issues.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/configure-ubuntu" ~/.claude/skills/majiayu000-claude-skill-registry-configure-ubuntu && rm -rf "$T"
skills/data/configure-ubuntu/SKILL.mdConfigure Ubuntu Skill
Purpose
This skill provides guidance for configuring Ubuntu LTS servers via cloud-init automation for any cloud platform (AWS, Azure, GCP, DigitalOcean, etc.).
Note: All examples in this skill currently use Ubuntu 24.04 LTS. Update version-specific package names or paths as needed for other LTS releases.
When to Use This Skill
Use this skill when:
- Writing cloud-init YAML for VM provisioning
- Configuring systemd services
- Setting up nginx reverse proxies
- Troubleshooting cloud-init or systemd issues
- Setting file permissions for service users
Reference Selection Guide
Choose the appropriate reference based on your task:
| Task | Reference File |
|---|---|
| Complete cloud-init configurations | |
| Cloud-init syntax and patterns | |
| systemd service units | |
| Debugging failures or errors | |
Ready-to-Use Examples
| Example | File |
|---|---|
| SSH bastion host | |
| Nginx reverse proxy (HTTP) | ← default |
| Nginx reverse proxy (HTTPS, self-signed) | |
| Nginx reverse proxy (HTTPS, Let's Encrypt) | |
| Nginx static file server | |
| Python/Flask server | |
| Node.js server | |
| Java/Spring Boot server | |
| .NET server | |
HTTPS Options:
- Use
by default (no SSL)proxy-http.yaml- Use
for self-signed certificates (development/internal)proxy-https.yaml- Use
for trusted certificates (requires domain name)proxy-https-letsencrypt.yaml
When to Read Multiple References
- New VM setup: Start with relevant example, then cloud-init-patterns.md for customization
- Service won't start: common-pitfalls.md + systemd-patterns.md
- SSH access broken: common-pitfalls.md (Issue #1)
- Permission denied errors: common-pitfalls.md (Issues #4, #5, #6)
- Scheduled tasks: systemd-patterns.md (Systemd Timers section)
- Production HTTPS: proxy-https-letsencrypt.yaml (requires domain name)
- Static website: static-files.yaml + proxy-http.yaml (if reverse proxy needed)
Critical Rules (Memorize These)
These rules prevent the most common failures:
- NEVER use
directive in cloud-init — Deletes default SSH user, breaks accessusers: - Systemd: NO inline comments —
failsAfter=network.target # comment - Permissions as quoted strings — Use
not'0640'
in cloud-init0640 - Wait for cloud-init — Takes 2-3 minutes; don't deploy until done
- Absolute paths in systemd — Use
not/opt/app/venv/bin/pythonpython - Fix permissions after SCP — Files copied retain local permissions
Default Choices for Vague Requests
When the request is ambiguous, use these defaults:
| Decision | Default Choice | Rationale |
|---|---|---|
| Application framework | Flask/Python | Course standard, most examples |
| Reverse proxy | HTTP (not HTTPS) | Simpler, use |
| Application port | 5001 | Avoids conflict with common ports |
| Proxy port | 80 (HTTP) or 443 (HTTPS) | Standard web ports |
| App directory | | Standard for third-party apps |
| Config directory | | Standard for system config |
| Service user | | Same as app, no login shell |
| Ownership pattern | | Deploy user writes, service reads |
| Directory permissions | 775 | Group can write (venv installs) |
| Config file permissions | 640 | Owner writes, group reads |
| WSGI server | Gunicorn | Production-ready, simple config |
Example Defaults
"Set up a web application server" → Use:
for application VMexamples/flask.yaml
for proxy VMexamples/proxy-http.yaml- Port 5001 for Flask, port 80 for nginx
"Configure nginx" → Use:
(reverse proxy, not static files)examples/proxy-http.yaml- Unless HTTPS explicitly requested, then
proxy-https.yaml
"Set up a secure bastion" → Use:
(includes UFW + fail2ban)examples/bastion.yaml
Environment Variables Pattern
This is the standard way to handle environment variables (database credentials, API keys, connection strings) on the server.
Directory Structure
/etc/<app-name>/ └── environment # All environment variables for the application
Setup in Cloud-init
runcmd: # Create config directory owned by root, readable by app group - mkdir -p /etc/myapp - chown root:myapp /etc/myapp - chmod 750 /etc/myapp # Create environment file with restricted permissions - touch /etc/myapp/environment - chown root:myapp /etc/myapp/environment - chmod 640 /etc/myapp/environment
Reference from systemd
[Service] EnvironmentFile=/etc/myapp/environment
Environment File Format
# /etc/myapp/environment DATABASE_URL=postgresql://user:password@host:5432/dbname SECRET_KEY=your-secret-key-here API_KEY=external-service-api-key DEBUG=false
Why This Pattern?
| Concern | Solution |
|---|---|
| Security | File owned by , only readable by app group (mode ) |
| Separation | Config in , code in — different concerns, different locations |
| Deployment | Environment file can be updated without redeploying code |
| systemd integration | loads variables automatically |
Quick Reference Tables
Default SSH Users by Cloud Provider
| Provider | Default User |
|---|---|
| AWS (Amazon Linux) | |
| AWS (Ubuntu) | |
| Azure | |
| GCP | Your Google account username |
| DigitalOcean | |
| Linode | |
File Permission Patterns
| Purpose | Owner:Group | Mode |
|---|---|---|
| Application code | deployuser:appgroup | 640 |
| Application directory | deployuser:appgroup | 775 |
| Config with secrets | root:appgroup | 640 |
| Config directory | root:appgroup | 750 |
| systemd service files | root:root | 644 |
Common systemctl Commands
sudo systemctl daemon-reload # After editing service files sudo systemctl enable myapp # Start on boot sudo systemctl start myapp # Start now sudo systemctl status myapp # Check status sudo journalctl -u myapp -f # Follow logs
Cloud-init Verification
cloud-init status # Check status cloud-init status --wait # Block until complete sudo cat /var/log/cloud-init-output.log # View logs
Reference Summaries
examples/ directory
Ready-to-use cloud-init YAML files for common server types. Copy and customize for your use case.
cloud-init-patterns.md
Reference documentation for cloud-init syntax:
- Module execution order
- Package management (
,packages
)package_update - Writing configuration files (
)write_files - Running commands (
)runcmd - Debugging and lifecycle
systemd-patterns.md
Reference documentation for systemd services:
- Service unit file structure (
,[Unit]
,[Service]
)[Install] - Service types (
,simple
,forking
)oneshot - Environment configuration
- Restart policies and resource limits
- Systemd timers (scheduled tasks, replacement for cron)
- Managing and debugging services
common-pitfalls.md
Prevention checklist and solutions for:
- Cloud-init issues (user deletion, timing)
- systemd issues (inline comments, permissions)
- File permission problems
- SSH and networking issues