Init
This commit is contained in:
499
Personal/Areas/Servers/TrueNAS/Docker Gitea with Traefik.md
Normal file
499
Personal/Areas/Servers/TrueNAS/Docker Gitea with Traefik.md
Normal file
@@ -0,0 +1,499 @@
|
||||
# Docker Gitea with Traefik Setup
|
||||
|
||||
## Overview
|
||||
|
||||
Complete setup for self-hosted Gitea with Traefik reverse proxy for secure external access on TrueNAS Scale.
|
||||
|
||||
**Stack:**
|
||||
- Gitea (Git server)
|
||||
- Traefik (Reverse proxy with automatic SSL)
|
||||
- Docker Compose
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Domain name** (or subdomain) pointed to your public IP
|
||||
- Example: `git.yourdomain.com`
|
||||
- Can use free services like DuckDNS, Cloudflare, etc.
|
||||
|
||||
2. **Port forwarding** on your router
|
||||
- Port 80 (HTTP) → TrueNAS IP
|
||||
- Port 443 (HTTPS) → TrueNAS IP
|
||||
|
||||
3. **SSH access** to TrueNAS Scale
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Create Datasets
|
||||
|
||||
SSH into TrueNAS and create storage locations:
|
||||
|
||||
```bash
|
||||
# Create main directory for docker compose projects
|
||||
cd /mnt/[your-pool-name]
|
||||
mkdir -p docker/gitea
|
||||
mkdir -p docker/traefik
|
||||
|
||||
# Create data directories
|
||||
mkdir -p docker/gitea/data
|
||||
mkdir -p docker/traefik/letsencrypt
|
||||
```
|
||||
|
||||
Or create via TrueNAS web UI:
|
||||
- Storage → Create Dataset → `docker`
|
||||
- Then create subdirectories via SSH or UI
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Traefik Configuration
|
||||
|
||||
### Create Traefik Config Directory
|
||||
|
||||
```bash
|
||||
cd /mnt/[your-pool-name]/docker/traefik
|
||||
```
|
||||
|
||||
### Create `traefik.yml`
|
||||
|
||||
```yaml
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: false
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
scheme: https
|
||||
websecure:
|
||||
address: ":443"
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: "unix:///var/run/docker.sock"
|
||||
exposedByDefault: false
|
||||
network: traefik_proxy
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: your-email@example.com
|
||||
storage: /letsencrypt/acme.json
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
```
|
||||
|
||||
### Create `docker-compose.yml` for Traefik
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
name: traefik_proxy
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v2.10
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- traefik_proxy
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
environment:
|
||||
- TZ=America/New_York # Adjust to your timezone
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./traefik.yml:/traefik.yml:ro
|
||||
- ./letsencrypt:/letsencrypt
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# Dashboard
|
||||
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
|
||||
- "traefik.http.routers.traefik.entrypoints=websecure"
|
||||
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.traefik.service=api@internal"
|
||||
# Basic auth for dashboard (optional but recommended)
|
||||
# Generate password: echo $(htpasswd -nb admin yourpassword) | sed -e s/\\$/\\$\\$/g
|
||||
- "traefik.http.routers.traefik.middlewares=traefik-auth"
|
||||
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$xyz$$abc123" # Replace with your hash
|
||||
```
|
||||
|
||||
### Start Traefik
|
||||
|
||||
```bash
|
||||
cd /mnt/[your-pool-name]/docker/traefik
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Gitea with Traefik Integration
|
||||
|
||||
### Create `docker-compose.yml` for Gitea
|
||||
|
||||
```bash
|
||||
cd /mnt/[your-pool-name]/docker/gitea
|
||||
```
|
||||
|
||||
Create `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true
|
||||
gitea_internal:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=sqlite3
|
||||
- GITEA__server__DOMAIN=git.yourdomain.com
|
||||
- GITEA__server__SSH_DOMAIN=git.yourdomain.com
|
||||
- GITEA__server__ROOT_URL=https://git.yourdomain.com
|
||||
- GITEA__server__SSH_PORT=2222
|
||||
- GITEA__server__SSH_LISTEN_PORT=22
|
||||
networks:
|
||||
- traefik_proxy
|
||||
- gitea_internal
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "2222:22" # SSH for git operations
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_proxy"
|
||||
# HTTP/HTTPS
|
||||
- "traefik.http.routers.gitea.rule=Host(`git.yourdomain.com`)"
|
||||
- "traefik.http.routers.gitea.entrypoints=websecure"
|
||||
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
|
||||
```
|
||||
|
||||
### Start Gitea
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Router Configuration
|
||||
|
||||
### Port Forwarding Rules
|
||||
|
||||
On your router, forward these ports to your TrueNAS IP:
|
||||
|
||||
| External Port | Internal Port | Protocol | Service |
|
||||
|--------------|---------------|----------|---------|
|
||||
| 80 | 80 | TCP | HTTP (Traefik) |
|
||||
| 443 | 443 | TCP | HTTPS (Traefik) |
|
||||
| 2222 | 2222 | TCP | SSH (Git operations) |
|
||||
|
||||
---
|
||||
|
||||
## Step 5: DNS Configuration
|
||||
|
||||
Point your domain/subdomain to your public IP:
|
||||
|
||||
### Option A: Cloudflare (Recommended)
|
||||
1. Add A record: `git.yourdomain.com` → Your public IP
|
||||
2. Optional: Enable Cloudflare proxy (orange cloud)
|
||||
- Pros: DDoS protection, caching
|
||||
- Cons: Need to configure Traefik for Cloudflare SSL
|
||||
|
||||
### Option B: DuckDNS (Free Dynamic DNS)
|
||||
1. Create account at duckdns.org
|
||||
2. Create subdomain: `yourname.duckdns.org`
|
||||
3. Set up auto-update script on TrueNAS for dynamic IP
|
||||
|
||||
### Option C: Your Domain Registrar
|
||||
1. Add A record: `git` → Your public IP
|
||||
2. Wait for DNS propagation (up to 24 hours)
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Initial Gitea Setup
|
||||
|
||||
1. Navigate to `https://git.yourdomain.com`
|
||||
2. Complete first-time setup wizard:
|
||||
- **Database:** SQLite (default is fine for personal use)
|
||||
- **SSH Server Domain:** `git.yourdomain.com`
|
||||
- **SSH Port:** `2222`
|
||||
- **Base URL:** `https://git.yourdomain.com`
|
||||
- **Disable registration** (personal use only)
|
||||
- Create admin account
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Configure Git Client
|
||||
|
||||
### SSH Config
|
||||
|
||||
Add to `~/.ssh/config`:
|
||||
|
||||
```
|
||||
Host git.yourdomain.com
|
||||
HostName git.yourdomain.com
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519 # Or your SSH key
|
||||
```
|
||||
|
||||
### Add SSH Key to Gitea
|
||||
|
||||
1. Generate SSH key (if needed):
|
||||
```bash
|
||||
ssh-keygen -t ed25519 -C "your-email@example.com"
|
||||
```
|
||||
|
||||
2. Copy public key:
|
||||
```bash
|
||||
cat ~/.ssh/id_ed25519.pub
|
||||
```
|
||||
|
||||
3. In Gitea: Settings → SSH/GPG Keys → Add Key
|
||||
|
||||
### Test SSH Connection
|
||||
|
||||
```bash
|
||||
ssh -T git@git.yourdomain.com
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```
|
||||
Hi there, username! You've successfully authenticated...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Usage Examples
|
||||
|
||||
### Clone Repository
|
||||
|
||||
```bash
|
||||
# HTTPS
|
||||
git clone https://git.yourdomain.com/username/repo.git
|
||||
|
||||
# SSH (recommended)
|
||||
git clone git@git.yourdomain.com:username/repo.git
|
||||
```
|
||||
|
||||
### Push Existing Repository
|
||||
|
||||
```bash
|
||||
cd /path/to/your/repo
|
||||
git remote add origin git@git.yourdomain.com:username/repo.git
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Strategy
|
||||
|
||||
### Manual Backup
|
||||
|
||||
```bash
|
||||
# Stop Gitea
|
||||
cd /mnt/[your-pool-name]/docker/gitea
|
||||
docker compose down
|
||||
|
||||
# Backup data directory
|
||||
tar -czf gitea-backup-$(date +%Y%m%d).tar.gz data/
|
||||
|
||||
# Restart Gitea
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Automated Backup (Gitea Built-in)
|
||||
|
||||
Create cron job on TrueNAS:
|
||||
|
||||
```bash
|
||||
# Add to crontab (System Settings → Advanced → Cron Jobs in TrueNAS UI)
|
||||
0 2 * * * docker exec gitea gitea dump -c /data/gitea/conf/app.ini -f /data/gitea-backup-$(date +\%Y\%m\%d).zip
|
||||
```
|
||||
|
||||
### TrueNAS Snapshots
|
||||
|
||||
- Enable periodic snapshots for `docker/gitea` dataset
|
||||
- Retention: Daily for 7 days, weekly for 4 weeks
|
||||
- Optional: Replicate to another location
|
||||
|
||||
---
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Update Containers
|
||||
|
||||
```bash
|
||||
# Traefik
|
||||
cd /mnt/[your-pool-name]/docker/traefik
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
|
||||
# Gitea
|
||||
cd /mnt/[your-pool-name]/docker/gitea
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# Traefik
|
||||
docker logs traefik -f
|
||||
|
||||
# Gitea
|
||||
docker logs gitea -f
|
||||
```
|
||||
|
||||
### Restart Services
|
||||
|
||||
```bash
|
||||
# Restart Gitea
|
||||
docker restart gitea
|
||||
|
||||
# Restart Traefik
|
||||
docker restart traefik
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Hardening
|
||||
|
||||
### 1. Disable Gitea Registration
|
||||
|
||||
In Gitea settings or `app.ini`:
|
||||
```ini
|
||||
[service]
|
||||
DISABLE_REGISTRATION = true
|
||||
REQUIRE_SIGNIN_VIEW = true # Optional: require login to view
|
||||
```
|
||||
|
||||
### 2. Fail2Ban (Optional)
|
||||
|
||||
Protect against brute force attacks:
|
||||
```bash
|
||||
# Install fail2ban on TrueNAS
|
||||
# Configure jail for Gitea SSH attempts
|
||||
```
|
||||
|
||||
### 3. Firewall Rules
|
||||
|
||||
On TrueNAS, restrict access if needed:
|
||||
```bash
|
||||
# Only allow specific IPs (example)
|
||||
iptables -A INPUT -p tcp --dport 2222 -s YOUR_IP -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 2222 -j DROP
|
||||
```
|
||||
|
||||
### 4. Regular Updates
|
||||
|
||||
- Update Docker images monthly
|
||||
- Monitor Gitea security advisories
|
||||
- Keep TrueNAS Scale updated
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### SSL Certificate Not Generated
|
||||
|
||||
**Check Traefik logs:**
|
||||
```bash
|
||||
docker logs traefik | grep -i error
|
||||
```
|
||||
|
||||
**Common issues:**
|
||||
- Port 80/443 not properly forwarded
|
||||
- DNS not pointing to your IP
|
||||
- Email in traefik.yml incorrect
|
||||
- Firewall blocking ports
|
||||
|
||||
### Can't Access Externally
|
||||
|
||||
1. Verify port forwarding on router
|
||||
2. Check public IP: `curl ifconfig.me`
|
||||
3. Test DNS: `nslookup git.yourdomain.com`
|
||||
4. Check Traefik dashboard for routes
|
||||
|
||||
### SSH Clone Not Working
|
||||
|
||||
1. Verify port 2222 is forwarded
|
||||
2. Test: `nc -zv git.yourdomain.com 2222`
|
||||
3. Check SSH key is added in Gitea
|
||||
4. Verify SSH config (~/.ssh/config)
|
||||
|
||||
### Gitea Container Won't Start
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker logs gitea
|
||||
|
||||
# Common issues:
|
||||
# - Port conflicts (3000 or 2222 in use)
|
||||
# - Permission issues on data directory
|
||||
# - Network conflicts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resource Usage
|
||||
|
||||
Expected usage on your i7-1065G7 with 16GB RAM:
|
||||
|
||||
- **Traefik:** ~30-50 MB RAM, minimal CPU
|
||||
- **Gitea:** ~100-150 MB RAM, <5% CPU (idle)
|
||||
- **Total:** ~150-200 MB RAM combined
|
||||
|
||||
Plenty of headroom for other services!
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [ ] Decide on domain name (purchase or use DuckDNS)
|
||||
- [ ] Create datasets on TrueNAS
|
||||
- [ ] Set up Traefik with docker-compose
|
||||
- [ ] Configure DNS records
|
||||
- [ ] Set up router port forwarding
|
||||
- [ ] Deploy Gitea container
|
||||
- [ ] Complete Gitea initial setup
|
||||
- [ ] Configure SSH keys
|
||||
- [ ] Test external access
|
||||
- [ ] Set up automated backups
|
||||
- [ ] Migrate repositories from GitHub
|
||||
|
||||
---
|
||||
|
||||
## Additional Services to Consider
|
||||
|
||||
Once Traefik is set up, you can easily add more services:
|
||||
|
||||
- **Uptime Kuma** - Monitoring dashboard
|
||||
- **Vaultwarden** - Self-hosted Bitwarden
|
||||
- **Nextcloud** - File sync and sharing
|
||||
- **Portainer** - Docker management UI
|
||||
- **Homer/Heimdall** - Homepage dashboard
|
||||
|
||||
All use the same Traefik setup for automatic SSL!
|
||||
193
Personal/Areas/Servers/TrueNAS/Git Server Options.md
Normal file
193
Personal/Areas/Servers/TrueNAS/Git Server Options.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# Git Server Options for TrueNAS
|
||||
|
||||
## Overview
|
||||
|
||||
Options for self-hosting a git server on TrueNAS, with considerations for features, complexity, and resource requirements.
|
||||
|
||||
---
|
||||
|
||||
## Option 1: Gitea
|
||||
|
||||
**Type:** Lightweight, self-hosted Git service
|
||||
|
||||
**Pros:**
|
||||
- Lightweight and fast (written in Go)
|
||||
- GitHub-like web interface
|
||||
- Easy installation via Docker/jail
|
||||
- Built-in CI/CD (Gitea Actions)
|
||||
- User management, organizations, teams
|
||||
- Issue tracking, wiki, pull requests
|
||||
- Low resource usage (~100-200 MB RAM)
|
||||
- Active development and community
|
||||
|
||||
**Cons:**
|
||||
- Fewer features than GitLab
|
||||
- Smaller plugin ecosystem
|
||||
|
||||
**Installation:**
|
||||
- TrueNAS Scale: Deploy via TrueCharts or Docker
|
||||
- TrueNAS Core: Install in FreeBSD jail
|
||||
|
||||
**Best For:** Most home users wanting a full-featured Git platform with minimal overhead
|
||||
|
||||
---
|
||||
|
||||
## Option 2: GitLab CE (Community Edition)
|
||||
|
||||
**Type:** Full-featured DevOps platform
|
||||
|
||||
**Pros:**
|
||||
- Complete DevOps lifecycle (CI/CD, container registry, etc.)
|
||||
- Professional features (protected branches, merge requests)
|
||||
- Excellent documentation
|
||||
- Industry-standard platform
|
||||
- Built-in runners for automation
|
||||
|
||||
**Cons:**
|
||||
- Resource-heavy (minimum 4GB RAM, recommend 8GB+)
|
||||
- Slower performance on modest hardware
|
||||
- More complex to maintain
|
||||
- Overkill for simple git hosting
|
||||
|
||||
**Installation:**
|
||||
- TrueNAS Scale: Docker container or VM
|
||||
- Requires dedicated resources
|
||||
|
||||
**Best For:** Users who want enterprise features and have hardware to spare
|
||||
|
||||
---
|
||||
|
||||
## Option 3: Plain Git Server (SSH-based)
|
||||
|
||||
**Type:** Bare-bones git via SSH
|
||||
|
||||
**Pros:**
|
||||
- Minimal resource usage
|
||||
- Simple and reliable
|
||||
- No web interface complexity
|
||||
- Uses native TrueNAS SSH access
|
||||
- Maximum control
|
||||
|
||||
**Cons:**
|
||||
- No web UI
|
||||
- No pull requests, issues, or collaboration features
|
||||
- Manual user/permission management
|
||||
- Command-line only workflow
|
||||
|
||||
**Setup:**
|
||||
```bash
|
||||
# Create git user and repos directory
|
||||
# Set up SSH keys
|
||||
# Initialize bare repos
|
||||
```
|
||||
|
||||
**Best For:** Solo users or small teams comfortable with CLI-only workflow
|
||||
|
||||
---
|
||||
|
||||
## Option 4: Gogs
|
||||
|
||||
**Type:** Painless self-hosted Git service (Gitea's predecessor)
|
||||
|
||||
**Pros:**
|
||||
- Even lighter than Gitea
|
||||
- Simple and stable
|
||||
- Easy to set up
|
||||
- Web interface for basic operations
|
||||
|
||||
**Cons:**
|
||||
- Less actively developed (Gitea forked from it)
|
||||
- Fewer features than Gitea
|
||||
- Smaller community
|
||||
|
||||
**Best For:** Users wanting minimal resource usage with basic web UI
|
||||
|
||||
---
|
||||
|
||||
## Option 5: cgit + gitolite
|
||||
|
||||
**Type:** Lightweight web viewer + access control
|
||||
|
||||
**Pros:**
|
||||
- Extremely lightweight
|
||||
- Fast repository browsing (cgit)
|
||||
- Fine-grained access control (gitolite)
|
||||
- Battle-tested and stable
|
||||
|
||||
**Cons:**
|
||||
- More complex initial setup
|
||||
- No modern collaboration features
|
||||
- Basic web interface (read-only)
|
||||
- Steeper learning curve
|
||||
|
||||
**Best For:** Advanced users prioritizing performance and control
|
||||
|
||||
---
|
||||
|
||||
## Comparison Matrix
|
||||
|
||||
| Feature | Gitea | GitLab CE | Plain Git | Gogs | cgit+gitolite |
|
||||
|---------|-------|-----------|-----------|------|---------------|
|
||||
| Resource Usage | Low | High | Minimal | Very Low | Minimal |
|
||||
| Web UI | Excellent | Excellent | None | Good | Basic |
|
||||
| Pull Requests | Yes | Yes | No | Yes | No |
|
||||
| CI/CD | Yes | Yes | No | No | No |
|
||||
| Setup Complexity | Easy | Medium | Easy | Easy | Hard |
|
||||
| Active Development | High | High | N/A | Low | Low |
|
||||
|
||||
---
|
||||
|
||||
## Recommendation
|
||||
|
||||
**For most home users: Gitea**
|
||||
|
||||
Reasons:
|
||||
- Best balance of features and resource usage
|
||||
- Modern, intuitive interface
|
||||
- Easy to maintain
|
||||
- Supports collaboration features (PRs, issues)
|
||||
- Works well on modest hardware
|
||||
- Can grow with your needs
|
||||
|
||||
**Installation on TrueNAS Scale:**
|
||||
1. Use TrueCharts app or custom Docker container
|
||||
2. Allocate dataset for persistent storage
|
||||
3. Configure reverse proxy (optional, for HTTPS)
|
||||
4. Set up backups of git repositories
|
||||
|
||||
---
|
||||
|
||||
## Additional Considerations
|
||||
|
||||
### Backup Strategy
|
||||
- Git repositories are already distributed backups
|
||||
- Still recommended to backup Gitea database and repos
|
||||
- TrueNAS snapshots + replication to another location
|
||||
|
||||
### Access Methods
|
||||
- SSH: Direct git operations
|
||||
- HTTPS: Web interface + git operations
|
||||
- Consider reverse proxy (Nginx/Traefik) for SSL
|
||||
|
||||
### Storage Requirements
|
||||
- Minimal for code repos (MBs to low GBs)
|
||||
- LFS (Large File Storage) if storing binaries/media
|
||||
- Plan for growth if hosting many repos
|
||||
|
||||
### Security
|
||||
- Keep software updated
|
||||
- Use SSH keys or strong passwords
|
||||
- Consider VPN for external access
|
||||
- Regular backups
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [ ] Decide on git server solution
|
||||
- [ ] Plan resource allocation (RAM, CPU, storage)
|
||||
- [ ] Choose access method (local only vs. external)
|
||||
- [ ] Set up TrueNAS dataset for git storage
|
||||
- [ ] Install and configure chosen solution
|
||||
- [ ] Configure backup strategy
|
||||
- [ ] Migrate existing repositories (if any)
|
||||
251
Personal/Areas/Servers/TrueNAS/Gitea Setup.md
Normal file
251
Personal/Areas/Servers/TrueNAS/Gitea Setup.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Gitea Setup on TrueNAS Scale
|
||||
|
||||
## Installation Options
|
||||
|
||||
### Option 1: TrueNAS Scale Apps (Recommended for Beginners)
|
||||
|
||||
TrueNAS Scale has a built-in app catalog that includes Gitea.
|
||||
|
||||
**Steps:**
|
||||
1. Navigate to **Apps** in TrueNAS Scale web UI
|
||||
2. Search for "Gitea"
|
||||
3. Click **Install**
|
||||
4. Configure:
|
||||
- **Application Name:** gitea
|
||||
- **Storage:** Create new dataset or use existing
|
||||
- **Network:** Bridge or Host networking
|
||||
- **Port:** 3000 (web UI), 22 (SSH) - adjust if conflicts
|
||||
5. Click **Install** and wait for deployment
|
||||
|
||||
**Pros:**
|
||||
- GUI-based installation
|
||||
- Automatic updates via TrueNAS
|
||||
- Integrated with TrueNAS management
|
||||
|
||||
**Cons:**
|
||||
- Less control over configuration
|
||||
- May lag behind latest Gitea releases
|
||||
|
||||
---
|
||||
|
||||
### Option 2: Custom Docker Container (More Control)
|
||||
|
||||
Using TrueNAS Scale's Docker support for more customization.
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. **Create Dataset**
|
||||
```
|
||||
Storage → Create Dataset
|
||||
Name: gitea_data
|
||||
```
|
||||
|
||||
2. **Create docker-compose.yml** (or use TrueNAS Apps → Discover)
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
environment:
|
||||
- USER_UID=568
|
||||
- USER_GID=568
|
||||
- GITEA__database__DB_TYPE=sqlite3
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /mnt/pool/gitea_data:/data
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "2222:22"
|
||||
```
|
||||
|
||||
3. **Deploy via Portainer or CLI**
|
||||
|
||||
**Pros:**
|
||||
- Full control over versions and configuration
|
||||
- Easy to backup and migrate
|
||||
- Can use docker-compose for multi-container setup
|
||||
|
||||
**Cons:**
|
||||
- More manual setup
|
||||
- Need to manage updates yourself
|
||||
|
||||
---
|
||||
|
||||
### Option 3: Kubernetes Deployment (Advanced)
|
||||
|
||||
TrueNAS Scale runs on Kubernetes, so you can deploy Gitea charts directly.
|
||||
|
||||
**Only recommended if you're familiar with Kubernetes**
|
||||
|
||||
---
|
||||
|
||||
## Initial Configuration
|
||||
|
||||
After installation, access Gitea at `http://[truenas-ip]:3000`
|
||||
|
||||
### First-Time Setup Wizard
|
||||
|
||||
1. **Database Settings:**
|
||||
- SQLite3 (default, easiest for small setups)
|
||||
- Or PostgreSQL/MySQL for better performance
|
||||
|
||||
2. **General Settings:**
|
||||
- Site Title: "Your Name's Git"
|
||||
- Repository Root Path: `/data/git/repositories` (default)
|
||||
- Git LFS Root Path: `/data/git/lfs` (default)
|
||||
|
||||
3. **Server and Third-Party Settings:**
|
||||
- SSH Server Domain: Your TrueNAS IP or hostname
|
||||
- SSH Port: 22 (or 2222 if using custom setup)
|
||||
- Gitea HTTP Listen Port: 3000
|
||||
- Gitea Base URL: `http://[your-ip]:3000/`
|
||||
|
||||
4. **Administrator Account:**
|
||||
- Create your admin user
|
||||
- Set secure password
|
||||
|
||||
5. Click **Install Gitea**
|
||||
|
||||
---
|
||||
|
||||
## Post-Installation Configuration
|
||||
|
||||
### 1. SSH Access for Git Operations
|
||||
|
||||
**If using port 2222 (recommended to avoid conflicts):**
|
||||
|
||||
Add to your `~/.ssh/config`:
|
||||
```
|
||||
Host git.home
|
||||
HostName [truenas-ip]
|
||||
Port 2222
|
||||
User git
|
||||
```
|
||||
|
||||
Then clone repos with:
|
||||
```bash
|
||||
git clone git@git.home:username/repo.git
|
||||
```
|
||||
|
||||
### 2. HTTPS Access (Optional but Recommended)
|
||||
|
||||
**Option A: Reverse Proxy (Nginx Proxy Manager)**
|
||||
- Install Nginx Proxy Manager as another app
|
||||
- Create proxy host pointing to Gitea
|
||||
- Add SSL certificate (Let's Encrypt)
|
||||
|
||||
**Option B: Built-in HTTPS**
|
||||
- Configure in Gitea's `app.ini`
|
||||
- Requires SSL certificate
|
||||
|
||||
### 3. Configure Backups
|
||||
|
||||
**Gitea Data Locations:**
|
||||
- Repositories: `/data/git/repositories`
|
||||
- Database: `/data/gitea.db` (if using SQLite)
|
||||
- Configuration: `/data/gitea/conf/app.ini`
|
||||
|
||||
**TrueNAS Backup Strategy:**
|
||||
- Periodic snapshots of gitea_data dataset
|
||||
- Replication to another location
|
||||
- Or use Gitea's built-in backup command:
|
||||
```bash
|
||||
gitea dump -c /data/gitea/conf/app.ini
|
||||
```
|
||||
|
||||
### 4. Performance Tuning
|
||||
|
||||
With your 16GB RAM, default settings are fine. If you add many users:
|
||||
|
||||
Edit `app.ini`:
|
||||
```ini
|
||||
[server]
|
||||
LFS_START_SERVER = true
|
||||
|
||||
[cache]
|
||||
ENABLED = true
|
||||
ADAPTER = memory
|
||||
INTERVAL = 60
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_TYPE = bleve
|
||||
REPO_INDEXER_ENABLED = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Creating First Repository
|
||||
|
||||
1. Log into Gitea web UI
|
||||
2. Click **+** → **New Repository**
|
||||
3. Set name, description, visibility
|
||||
4. Initialize with README if desired
|
||||
5. Click **Create Repository**
|
||||
|
||||
### Pushing Existing Repo
|
||||
|
||||
```bash
|
||||
cd /path/to/your/repo
|
||||
git remote add origin http://[truenas-ip]:3000/username/repo.git
|
||||
# or git@git.home:username/repo.git for SSH
|
||||
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
### Migrating from GitHub
|
||||
|
||||
1. In Gitea: **+** → **New Migration**
|
||||
2. Select **GitHub**
|
||||
3. Enter repo URL
|
||||
4. Optionally: Add GitHub token for private repos
|
||||
5. Click **Migrate Repository**
|
||||
|
||||
---
|
||||
|
||||
## Resource Usage Expectations
|
||||
|
||||
With your hardware (i7-1065G7, 16GB RAM):
|
||||
|
||||
- **Gitea idle:** ~50-100 MB RAM
|
||||
- **Gitea active usage:** ~100-200 MB RAM
|
||||
- **CPU:** Minimal (<5% typically)
|
||||
|
||||
Plenty of headroom for other services.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Can't Access Web UI
|
||||
- Check firewall rules on TrueNAS
|
||||
- Verify container is running: Apps → Installed
|
||||
- Check logs in TrueNAS Apps UI
|
||||
|
||||
### SSH Clone Not Working
|
||||
- Verify SSH port is correct (22 or 2222)
|
||||
- Check SSH keys are added in Gitea: Settings → SSH/GPG Keys
|
||||
- Test SSH: `ssh -T git@[truenas-ip] -p [port]`
|
||||
|
||||
### Slow Performance
|
||||
- Check TrueNAS system resources (CPU, RAM, disk I/O)
|
||||
- Consider switching from SQLite to PostgreSQL for large repos
|
||||
- Enable Gitea caching (see Performance Tuning above)
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [ ] Choose installation method (TrueNAS App vs Custom Docker)
|
||||
- [ ] Create storage dataset for Gitea data
|
||||
- [ ] Install Gitea
|
||||
- [ ] Complete initial setup wizard
|
||||
- [ ] Create admin account
|
||||
- [ ] Configure SSH access
|
||||
- [ ] Set up backup strategy
|
||||
- [ ] Migrate existing repositories
|
||||
- [ ] (Optional) Set up HTTPS with reverse proxy
|
||||
- [ ] (Optional) Configure external access via VPN or port forwarding
|
||||
@@ -0,0 +1,358 @@
|
||||
# Integrating Servarr Stack with Traefik
|
||||
|
||||
## Your Current Setup
|
||||
|
||||
You have a Servarr media automation stack (`servarr.yaml`) with:
|
||||
- **Gluetun** - VPN container (ProtonVPN)
|
||||
- **qBittorrent** - Torrent client
|
||||
- **Sonarr/Radarr/Lidarr** - Media management
|
||||
- **Prowlarr** - Indexer manager
|
||||
- **Bazarr** - Subtitle downloader
|
||||
- **Recyclarr** - Configuration sync
|
||||
- **Dozzle** - Log viewer
|
||||
- **Watchtower** - Auto-updater
|
||||
|
||||
**Special consideration:** Most services use `network_mode: service:gluetun`, meaning they share gluetun's network namespace for VPN routing.
|
||||
|
||||
---
|
||||
|
||||
## Challenge: VPN Network Mode
|
||||
|
||||
Services using `network_mode: service:gluetun` **cannot** directly connect to the `traefik_proxy` network. They're locked into gluetun's network namespace for VPN routing.
|
||||
|
||||
### Options for External Access
|
||||
|
||||
**Option 1: Don't Expose VPN Services Externally (Recommended)**
|
||||
- Keep VPN-routed services local-only
|
||||
- Access via local network or Tailscale/Wireguard
|
||||
- Most secure approach
|
||||
- Expose only Dozzle (log viewer) via Traefik for monitoring
|
||||
|
||||
**Option 2: Expose Gluetun to Traefik**
|
||||
- Connect gluetun container to Traefik network
|
||||
- Route to services through gluetun's exposed ports
|
||||
- More complex configuration
|
||||
- Potential security considerations
|
||||
|
||||
**Option 3: Split the Stack**
|
||||
- Keep VPN services in current stack (local-only)
|
||||
- Move non-VPN services (Dozzle) to separate stack for Traefik access
|
||||
|
||||
---
|
||||
|
||||
## Recommended Approach: Hybrid Setup
|
||||
|
||||
### Keep VPN Services Local, Expose Dozzle via Traefik
|
||||
|
||||
This gives you:
|
||||
- ✅ Secure VPN routing for download/automation apps (local access only)
|
||||
- ✅ External access to Dozzle for log monitoring
|
||||
- ✅ Simple configuration
|
||||
- ✅ No VPN security compromise
|
||||
|
||||
---
|
||||
|
||||
## Implementation
|
||||
|
||||
### Current Directory Structure
|
||||
|
||||
```
|
||||
/mnt/tank/
|
||||
├── configs/
|
||||
│ ├── gluetun/
|
||||
│ ├── qbittorrent/
|
||||
│ ├── sonarr/
|
||||
│ ├── radarr/
|
||||
│ ├── lidarr/
|
||||
│ ├── prowlarr/
|
||||
│ ├── bazarr/
|
||||
│ ├── recyclarr/
|
||||
│ └── dozzle/
|
||||
└── media/
|
||||
```
|
||||
|
||||
### Modified servarr.yaml
|
||||
|
||||
**Keep the current file mostly as-is, but extract Dozzle to a separate stack:**
|
||||
|
||||
#### Step 1: Deploy Traefik (if not done)
|
||||
|
||||
See: [[Traefik Multi-Stack Setup#Step 1]]
|
||||
|
||||
#### Step 2: Split Dozzle to Separate Stack
|
||||
|
||||
**Remove Dozzle from `servarr.yaml`:**
|
||||
|
||||
```yaml
|
||||
# Remove this section from servarr.yaml:
|
||||
dozzle:
|
||||
image: amir20/dozzle:latest
|
||||
container_name: dozzle
|
||||
ports:
|
||||
- 9999:8080
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
**Create `/mnt/tank/stacks/dozzle/docker-compose.yml`:**
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true
|
||||
|
||||
services:
|
||||
dozzle:
|
||||
image: amir20/dozzle:latest
|
||||
container_name: dozzle
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- traefik_proxy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
environment:
|
||||
- TZ=Europe/Amsterdam
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_proxy"
|
||||
- "traefik.http.routers.dozzle.rule=Host(`logs.yourdomain.com`)"
|
||||
- "traefik.http.routers.dozzle.entrypoints=websecure"
|
||||
- "traefik.http.routers.dozzle.tls.certresolver=cloudflare"
|
||||
- "traefik.http.services.dozzle.loadbalancer.server.port=8080"
|
||||
# Optional: Add authentication
|
||||
- "traefik.http.routers.dozzle.middlewares=dozzle-auth"
|
||||
- "traefik.http.middlewares.dozzle-auth.basicauth.users=admin:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
```
|
||||
|
||||
**Deploy Dozzle:**
|
||||
```bash
|
||||
mkdir -p /mnt/tank/stacks/dozzle
|
||||
cd /mnt/tank/stacks/dozzle
|
||||
# Create docker-compose.yml with content above, then:
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Now accessible at: `https://logs.yourdomain.com`
|
||||
|
||||
#### Step 3: Keep Servarr Stack As-Is
|
||||
|
||||
Your VPN-routed services remain accessible on local network:
|
||||
- qBittorrent: `http://truenas-ip:8080`
|
||||
- Sonarr: `http://truenas-ip:8989`
|
||||
- Radarr: `http://truenas-ip:7878`
|
||||
- Prowlarr: `http://truenas-ip:9696`
|
||||
- Lidarr: `http://truenas-ip:8686`
|
||||
- Bazarr: `http://truenas-ip:6767`
|
||||
|
||||
**Access these via:**
|
||||
- Local network (current method)
|
||||
- VPN (Tailscale/Wireguard) for remote access
|
||||
- SSH tunnel for secure remote access
|
||||
|
||||
---
|
||||
|
||||
## Alternative: Expose Select Services via Traefik
|
||||
|
||||
If you want some *arr services accessible externally (e.g., Sonarr/Radarr for mobile apps):
|
||||
|
||||
### Option: Duplicate Ports in Gluetun
|
||||
|
||||
Add gluetun to Traefik network and route through it:
|
||||
|
||||
**Modified servarr.yaml:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
gluetun:
|
||||
image: qmcgaw/gluetun:latest
|
||||
container_name: gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
environment:
|
||||
- VPN_SERVICE_PROVIDER=protonvpn
|
||||
- VPN_TYPE=wireguard
|
||||
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
|
||||
- SERVER_COUNTRIES=Netherlands
|
||||
- TZ=Europe/Amsterdam
|
||||
volumes:
|
||||
- /mnt/tank/configs/gluetun:/gluetun
|
||||
- /mnt/tank/configs/gluetun-tmp:/tmp/gluetun
|
||||
ports:
|
||||
- 8080:8080 # qBittorrent
|
||||
- 7878:7878 # Radarr
|
||||
- 8686:8686 # Lidarr
|
||||
- 8989:8989 # Sonarr
|
||||
- 9696:9696 # Prowlarr
|
||||
- 6767:6767 # Bazarr
|
||||
networks:
|
||||
- traefik_proxy # Add this
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
# Sonarr via Traefik
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_proxy"
|
||||
- "traefik.http.routers.sonarr.rule=Host(`sonarr.yourdomain.com`)"
|
||||
- "traefik.http.routers.sonarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.sonarr.tls.certresolver=cloudflare"
|
||||
- "traefik.http.routers.sonarr.service=sonarr"
|
||||
- "traefik.http.services.sonarr.loadbalancer.server.port=8989"
|
||||
# Radarr via Traefik
|
||||
- "traefik.http.routers.radarr.rule=Host(`radarr.yourdomain.com`)"
|
||||
- "traefik.http.routers.radarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.radarr.tls.certresolver=cloudflare"
|
||||
- "traefik.http.routers.radarr.service=radarr"
|
||||
- "traefik.http.services.radarr.loadbalancer.server.port=7878"
|
||||
# Add more services as needed...
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true
|
||||
|
||||
# ... rest of services remain the same
|
||||
```
|
||||
|
||||
**Security Note:** This exposes your download apps to the internet. Consider:
|
||||
- Strong authentication in each app
|
||||
- Traefik basic auth middleware
|
||||
- Firewall rules limiting access to your IP
|
||||
- Or stick with VPN-only access
|
||||
|
||||
---
|
||||
|
||||
## Recommended Final Architecture
|
||||
|
||||
```
|
||||
Internet (Port 80/443)
|
||||
↓
|
||||
Traefik
|
||||
├── Gitea (https://git.yourdomain.com)
|
||||
├── Dozzle (https://logs.yourdomain.com)
|
||||
└── [Future Services]
|
||||
|
||||
Local Network Only:
|
||||
↓
|
||||
Servarr Stack (VPN-routed)
|
||||
├── Sonarr (http://truenas-ip:8989)
|
||||
├── Radarr (http://truenas-ip:7878)
|
||||
├── qBittorrent (http://truenas-ip:8080)
|
||||
└── [Other *arr apps]
|
||||
```
|
||||
|
||||
**Access Servarr remotely via:**
|
||||
- Tailscale/Wireguard VPN
|
||||
- SSH tunnel: `ssh -L 8989:localhost:8989 user@truenas-ip`
|
||||
|
||||
---
|
||||
|
||||
## Stack Management
|
||||
|
||||
### Servarr Stack
|
||||
|
||||
```bash
|
||||
# Start/stop Servarr stack
|
||||
cd /mnt/tank/stacks/servarr
|
||||
docker compose up -d
|
||||
docker compose down
|
||||
|
||||
# Update containers (Watchtower handles this automatically)
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Dozzle (Traefik-routed)
|
||||
|
||||
```bash
|
||||
cd /mnt/tank/stacks/dozzle
|
||||
docker compose up -d
|
||||
docker compose down
|
||||
```
|
||||
|
||||
### Gitea (Traefik-routed)
|
||||
|
||||
```bash
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose up -d
|
||||
docker compose down
|
||||
```
|
||||
|
||||
All stacks are independent!
|
||||
|
||||
---
|
||||
|
||||
## DNS Records for Cloudflare
|
||||
|
||||
Add A records:
|
||||
|
||||
| Name | Target | Proxy |
|
||||
|------|--------|-------|
|
||||
| git | Your-Public-IP | DNS only |
|
||||
| logs | Your-Public-IP | DNS only |
|
||||
| traefik | Your-Public-IP | DNS only |
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Create `.env` file in servarr directory for sensitive data:
|
||||
|
||||
```bash
|
||||
# /mnt/tank/stacks/servarr/.env
|
||||
WIREGUARD_PRIVATE_KEY=your-wireguard-key
|
||||
```
|
||||
|
||||
Reference in docker-compose:
|
||||
```yaml
|
||||
environment:
|
||||
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Don't expose VPN-routed services directly to internet**
|
||||
- Use Tailscale/Wireguard for remote access
|
||||
- Or use SSH tunnels
|
||||
|
||||
2. **Enable authentication on all services**
|
||||
- Each *arr app has built-in auth
|
||||
- Configure strong passwords
|
||||
|
||||
3. **Use Traefik middlewares for additional security**
|
||||
- Basic auth
|
||||
- IP whitelisting
|
||||
- Rate limiting
|
||||
|
||||
4. **Keep Watchtower for auto-updates**
|
||||
- Already configured in your stack
|
||||
- Keeps containers patched
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [ ] Deploy Traefik (if not already done)
|
||||
- [ ] Move Dozzle to separate stack with Traefik labels
|
||||
- [ ] Deploy Dozzle with external access
|
||||
- [ ] Keep Servarr services local-only (current setup)
|
||||
- [ ] Set up Tailscale/Wireguard for secure remote access to Servarr
|
||||
- [ ] Add DNS records for exposed services
|
||||
- [ ] Test accessing Dozzle externally
|
||||
- [ ] Configure authentication for all services
|
||||
|
||||
---
|
||||
|
||||
## Additional Notes
|
||||
|
||||
Your directory structure:
|
||||
|
||||
```
|
||||
/mnt/tank/stacks/
|
||||
├── traefik/
|
||||
├── gitea/
|
||||
├── servarr/ (your existing stack)
|
||||
└── dozzle/ (optional split from servarr)
|
||||
```
|
||||
330
Personal/Areas/Servers/TrueNAS/Quick Reference.md
Normal file
330
Personal/Areas/Servers/TrueNAS/Quick Reference.md
Normal file
@@ -0,0 +1,330 @@
|
||||
# TrueNAS Quick Reference
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Docker Management
|
||||
|
||||
```bash
|
||||
# View running containers
|
||||
docker ps
|
||||
|
||||
# View all containers (including stopped)
|
||||
docker ps -a
|
||||
|
||||
# View logs
|
||||
docker logs gitea -f # Follow logs
|
||||
docker logs traefik --tail 50 # Last 50 lines
|
||||
|
||||
# Restart containers
|
||||
docker restart gitea
|
||||
docker restart traefik
|
||||
|
||||
# Stop/Start with docker-compose
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
|
||||
# Update containers
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
|
||||
# Remove unused images
|
||||
docker image prune -a
|
||||
```
|
||||
|
||||
### TrueNAS Storage
|
||||
|
||||
```bash
|
||||
# Check pool status
|
||||
zpool status
|
||||
|
||||
# List datasets
|
||||
zfs list
|
||||
|
||||
# Create snapshot
|
||||
zfs snapshot [pool]/docker/gitea@$(date +%Y%m%d)
|
||||
|
||||
# List snapshots
|
||||
zfs list -t snapshot
|
||||
|
||||
# Restore from snapshot
|
||||
zfs rollback [pool]/docker/gitea@20250125
|
||||
```
|
||||
|
||||
### Network Troubleshooting
|
||||
|
||||
```bash
|
||||
# Check open ports
|
||||
netstat -tulpn | grep LISTEN
|
||||
|
||||
# Test external connectivity
|
||||
curl -I https://git.yourdomain.com
|
||||
|
||||
# Test DNS
|
||||
nslookup git.yourdomain.com
|
||||
|
||||
# Test port forwarding
|
||||
nc -zv git.yourdomain.com 2222
|
||||
|
||||
# Check public IP
|
||||
curl ifconfig.me
|
||||
```
|
||||
|
||||
### Gitea Specific
|
||||
|
||||
```bash
|
||||
# Enter Gitea container
|
||||
docker exec -it gitea sh
|
||||
|
||||
# Gitea CLI commands (inside container)
|
||||
gitea admin user list
|
||||
gitea admin user create --username newuser --email user@example.com --password changeme
|
||||
gitea dump # Create backup
|
||||
|
||||
# View Gitea config
|
||||
docker exec gitea cat /data/gitea/conf/app.ini
|
||||
```
|
||||
|
||||
### Traefik Specific
|
||||
|
||||
```bash
|
||||
# View Traefik config
|
||||
docker exec traefik cat /traefik.yml
|
||||
|
||||
# Check certificate
|
||||
docker exec traefik ls -la /letsencrypt
|
||||
|
||||
# Restart Traefik to reload config
|
||||
docker restart traefik
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Locations
|
||||
|
||||
### On TrueNAS Host
|
||||
|
||||
```
|
||||
/mnt/tank/stacks/
|
||||
├── traefik/
|
||||
│ ├── docker-compose.yml
|
||||
│ ├── traefik.yml
|
||||
│ └── letsencrypt/
|
||||
│ └── acme.json
|
||||
├── gitea/
|
||||
│ ├── docker-compose.yml
|
||||
│ └── data/
|
||||
│ ├── git/
|
||||
│ │ └── repositories/
|
||||
│ ├── gitea/
|
||||
│ │ └── conf/
|
||||
│ │ └── app.ini
|
||||
│ └── gitea.db
|
||||
└── servarr/
|
||||
└── docker-compose.yml
|
||||
```
|
||||
|
||||
### Important Config Files
|
||||
|
||||
- **Traefik config:** `/mnt/tank/stacks/traefik/traefik.yml`
|
||||
- **Gitea config:** `/mnt/tank/stacks/gitea/data/gitea/conf/app.ini`
|
||||
- **Gitea repos:** `/mnt/tank/stacks/gitea/data/git/repositories/`
|
||||
- **SSL certs:** `/mnt/tank/stacks/traefik/letsencrypt/acme.json`
|
||||
|
||||
---
|
||||
|
||||
## Quick Checks
|
||||
|
||||
### Is Everything Running?
|
||||
|
||||
```bash
|
||||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```
|
||||
NAMES STATUS PORTS
|
||||
gitea Up 2 days 0.0.0.0:2222->22/tcp, 3000/tcp
|
||||
traefik Up 2 days 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
|
||||
```
|
||||
|
||||
### Check Certificate Expiry
|
||||
|
||||
```bash
|
||||
echo | openssl s_client -servername git.yourdomain.com -connect git.yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates
|
||||
```
|
||||
|
||||
### Disk Usage
|
||||
|
||||
```bash
|
||||
# Docker disk usage
|
||||
docker system df
|
||||
|
||||
# Dataset usage
|
||||
zfs list | grep docker
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Commands
|
||||
|
||||
### Quick Gitea Backup
|
||||
|
||||
```bash
|
||||
# Create backup
|
||||
docker exec gitea gitea dump -c /data/gitea/conf/app.ini -f /data/gitea-backup-$(date +%Y%m%d).zip
|
||||
|
||||
# Copy backup off server
|
||||
docker cp gitea:/data/gitea-backup-$(date +%Y%m%d).zip /mnt/tank/backups/
|
||||
```
|
||||
|
||||
### Snapshot Entire Stacks Dataset
|
||||
|
||||
```bash
|
||||
# Create snapshot
|
||||
zfs snapshot tank/stacks@backup-$(date +%Y%m%d)
|
||||
|
||||
# Send to backup location
|
||||
zfs send tank/stacks@backup-$(date +%Y%m%d) | ssh backup-server "zfs recv backup/truenas-stacks"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Git Client Setup
|
||||
|
||||
### SSH Config (~/.ssh/config)
|
||||
|
||||
```
|
||||
Host git.yourdomain.com
|
||||
HostName git.yourdomain.com
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
```
|
||||
|
||||
### Common Git Operations
|
||||
|
||||
```bash
|
||||
# Clone via SSH
|
||||
git clone git@git.yourdomain.com:username/repo.git
|
||||
|
||||
# Clone via HTTPS
|
||||
git clone https://git.yourdomain.com/username/repo.git
|
||||
|
||||
# Add remote to existing repo
|
||||
git remote add origin git@git.yourdomain.com:username/repo.git
|
||||
|
||||
# Push
|
||||
git push -u origin main
|
||||
|
||||
# Test SSH connection
|
||||
ssh -T git@git.yourdomain.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Maintenance Schedule
|
||||
|
||||
### Weekly
|
||||
- [ ] Check container logs for errors
|
||||
- [ ] Verify backups completed
|
||||
|
||||
### Monthly
|
||||
- [ ] Update Docker containers
|
||||
- [ ] Check disk usage
|
||||
- [ ] Review Gitea security settings
|
||||
|
||||
### Quarterly
|
||||
- [ ] Test disaster recovery (restore from backup)
|
||||
- [ ] Review access logs
|
||||
- [ ] Update TrueNAS Scale
|
||||
|
||||
---
|
||||
|
||||
## Emergency Procedures
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker logs gitea --tail 100
|
||||
|
||||
# Remove and recreate
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Lost SSL Certificate
|
||||
|
||||
```bash
|
||||
# Remove acme.json to force renewal
|
||||
rm /mnt/tank/stacks/traefik/letsencrypt/acme.json
|
||||
docker restart traefik
|
||||
|
||||
# Wait a few minutes and check
|
||||
docker logs traefik | grep -i certificate
|
||||
```
|
||||
|
||||
### Corrupted Database
|
||||
|
||||
```bash
|
||||
# Stop Gitea
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose down
|
||||
|
||||
# Restore from snapshot
|
||||
zfs rollback tank/stacks/gitea@[snapshot-name]
|
||||
|
||||
# Or restore from Gitea backup
|
||||
cd /mnt/tank/stacks/gitea/data
|
||||
unzip gitea-backup-20250125.zip
|
||||
# Extract files to appropriate locations
|
||||
|
||||
# Restart
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Monitoring
|
||||
|
||||
```bash
|
||||
# Container stats
|
||||
docker stats
|
||||
|
||||
# TrueNAS resource usage
|
||||
top
|
||||
htop # If installed
|
||||
|
||||
# Check I/O
|
||||
iostat -x 5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Useful URLs
|
||||
|
||||
When services are running:
|
||||
|
||||
- **Gitea:** https://git.yourdomain.com
|
||||
- **Traefik Dashboard:** https://traefik.yourdomain.com (if configured)
|
||||
- **TrueNAS UI:** https://[truenas-ip]
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables Reference
|
||||
|
||||
Common environment variables for Gitea:
|
||||
|
||||
```yaml
|
||||
- GITEA__server__DOMAIN=git.yourdomain.com
|
||||
- GITEA__server__ROOT_URL=https://git.yourdomain.com
|
||||
- GITEA__server__SSH_PORT=2222
|
||||
- GITEA__service__DISABLE_REGISTRATION=true
|
||||
- GITEA__database__DB_TYPE=sqlite3
|
||||
- GITEA__repository__ENABLE_PUSH_CREATE_USER=true
|
||||
- GITEA__security__INSTALL_LOCK=true
|
||||
```
|
||||
|
||||
See [Gitea Config Cheat Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) for full list.
|
||||
287
Personal/Areas/Servers/TrueNAS/Recommended Setup.md
Normal file
287
Personal/Areas/Servers/TrueNAS/Recommended Setup.md
Normal file
@@ -0,0 +1,287 @@
|
||||
# Recommended Setup for Your TrueNAS
|
||||
|
||||
## Your Situation
|
||||
|
||||
- **Hardware:** i7-1065G7, 16GB RAM (plenty of resources)
|
||||
- **Domain:** Cloudflare-managed domain
|
||||
- **Requirements:**
|
||||
- Gitea for self-hosted Git
|
||||
- Existing Docker stack
|
||||
- External access via Traefik
|
||||
- Separate stacks (good practice!)
|
||||
|
||||
---
|
||||
|
||||
## Recommended Architecture
|
||||
|
||||
### Single Traefik Instance + Multiple Independent Stacks
|
||||
|
||||
```
|
||||
Internet (Port 80/443)
|
||||
↓
|
||||
Router Port Forwarding
|
||||
↓
|
||||
┌─────────────────────────────┐
|
||||
│ Traefik Container │
|
||||
│ - SSL Certificates │
|
||||
│ - Routing │
|
||||
└──────────┬──────────────────┘
|
||||
│ traefik_proxy network
|
||||
┌──────┼──────┐
|
||||
↓ ↓ ↓
|
||||
┌───────┐ ┌────────┐ ┌─────────┐
|
||||
│ Gitea │ │ Other │ │ Future │
|
||||
│ Stack │ │ Stack │ │ Service │
|
||||
└───────┘ └────────┘ └─────────┘
|
||||
```
|
||||
|
||||
**Each stack has its own:**
|
||||
- Directory: `/mnt/[pool]/docker/[service-name]/`
|
||||
- `docker-compose.yml`
|
||||
- Data volumes
|
||||
- Can be started/stopped/updated independently
|
||||
|
||||
**Shared:**
|
||||
- One Traefik instance handles routing for all
|
||||
- One `traefik_proxy` network connects everything
|
||||
- One SSL certificate manager (via Cloudflare DNS)
|
||||
|
||||
---
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### 1. Deploy Traefik (Once, First)
|
||||
|
||||
**Location:** `/mnt/tank/stacks/traefik/`
|
||||
|
||||
**Key features:**
|
||||
- Cloudflare DNS challenge for SSL (works even without port 80 exposed)
|
||||
- Dashboard at `traefik.yourdomain.com`
|
||||
- Automatic SSL renewal
|
||||
- HTTP → HTTPS redirect
|
||||
|
||||
**See:** [[Traefik Multi-Stack Setup#Step 1]]
|
||||
|
||||
### 2. Deploy Gitea Stack
|
||||
|
||||
**Location:** `/mnt/tank/stacks/gitea/`
|
||||
|
||||
**Connects to:** `traefik_proxy` network (external)
|
||||
|
||||
**Exposes:**
|
||||
- Port 2222 for SSH (git operations)
|
||||
- Port 3000 internally to Traefik (for web UI)
|
||||
|
||||
**Accessible at:** `https://git.yourdomain.com`
|
||||
|
||||
**See:** [[Traefik Multi-Stack Setup#Step 2]]
|
||||
|
||||
### 3. Connect Your Existing Stack
|
||||
|
||||
**Modify your existing stack's `docker-compose.yml`:**
|
||||
|
||||
1. Add external network reference:
|
||||
```yaml
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true
|
||||
```
|
||||
|
||||
2. Add network to your service:
|
||||
```yaml
|
||||
services:
|
||||
your-service:
|
||||
networks:
|
||||
- traefik_proxy
|
||||
```
|
||||
|
||||
3. Add Traefik labels:
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_proxy"
|
||||
- "traefik.http.routers.yourservice.rule=Host(`service.yourdomain.com`)"
|
||||
- "traefik.http.routers.yourservice.entrypoints=websecure"
|
||||
- "traefik.http.routers.yourservice.tls.certresolver=cloudflare"
|
||||
- "traefik.http.services.yourservice.loadbalancer.server.port=INTERNAL_PORT"
|
||||
```
|
||||
|
||||
4. Remove any exposed ports (Traefik handles routing)
|
||||
|
||||
**See:** [[Traefik Multi-Stack Setup#Step 3]]
|
||||
|
||||
---
|
||||
|
||||
## Cloudflare Configuration
|
||||
|
||||
### DNS Records
|
||||
|
||||
Add A records pointing to your public IP:
|
||||
|
||||
```
|
||||
git.yourdomain.com → Your-Public-IP (DNS only, gray cloud)
|
||||
traefik.yourdomain.com → Your-Public-IP (DNS only, gray cloud)
|
||||
service.yourdomain.com → Your-Public-IP (DNS only, gray cloud)
|
||||
```
|
||||
|
||||
**Important:** Use "DNS only" mode, not proxied (gray cloud, not orange).
|
||||
|
||||
### API Credentials
|
||||
|
||||
For Traefik to manage SSL certificates via Cloudflare DNS:
|
||||
|
||||
**Option 1: API Token (Recommended)**
|
||||
1. Cloudflare Dashboard → Profile → API Tokens
|
||||
2. Create Token → "Edit zone DNS" template
|
||||
3. Zone Resources: Include → Specific zone → yourdomain.com
|
||||
4. Use in Traefik: `CF_DNS_API_TOKEN`
|
||||
|
||||
**Option 2: Global API Key**
|
||||
1. Cloudflare Dashboard → Profile → API Tokens
|
||||
2. View Global API Key
|
||||
3. Use in Traefik: `CF_API_EMAIL` + `CF_API_KEY`
|
||||
|
||||
---
|
||||
|
||||
## Router Port Forwarding
|
||||
|
||||
One-time setup:
|
||||
|
||||
| External Port | Internal Port | Protocol | Target |
|
||||
|--------------|---------------|----------|--------|
|
||||
| 80 | 80 | TCP | TrueNAS IP |
|
||||
| 443 | 443 | TCP | TrueNAS IP |
|
||||
| 2222 | 2222 | TCP | TrueNAS IP |
|
||||
|
||||
**That's it!** All HTTP/HTTPS traffic goes to Traefik, which routes to the correct service based on domain name.
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
Your layout:
|
||||
|
||||
```
|
||||
/mnt/tank/stacks/
|
||||
├── traefik/
|
||||
│ ├── docker-compose.yml
|
||||
│ ├── traefik.yml
|
||||
│ └── letsencrypt/
|
||||
│ └── acme.json
|
||||
├── gitea/
|
||||
│ ├── docker-compose.yml
|
||||
│ └── data/
|
||||
├── servarr/
|
||||
│ ├── docker-compose.yml (or servarr.yaml)
|
||||
│ └── ...
|
||||
└── dozzle/ (optional split from servarr)
|
||||
└── docker-compose.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Benefits of This Setup
|
||||
|
||||
✅ **Independent stacks** - Update Gitea without touching other services
|
||||
✅ **One SSL manager** - Traefik handles certificates for all domains
|
||||
✅ **Easy to add services** - Just add labels and deploy
|
||||
✅ **Clean separation** - Each service in its own directory
|
||||
✅ **Professional setup** - Industry-standard architecture
|
||||
✅ **Low overhead** - Traefik uses ~30-50MB RAM
|
||||
✅ **Cloudflare integration** - DNS challenge works behind CGNAT
|
||||
|
||||
---
|
||||
|
||||
## Common Operations
|
||||
|
||||
### Start Everything
|
||||
|
||||
```bash
|
||||
# Start Traefik first
|
||||
cd /mnt/tank/stacks/traefik
|
||||
docker compose up -d
|
||||
|
||||
# Then start services in any order
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose up -d
|
||||
|
||||
cd /mnt/tank/stacks/servarr
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Update One Service
|
||||
|
||||
```bash
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
# Other services unaffected
|
||||
```
|
||||
|
||||
### Check Status
|
||||
|
||||
```bash
|
||||
# See all running services
|
||||
docker ps
|
||||
|
||||
# Check what's connected to Traefik
|
||||
docker network inspect traefik_proxy | grep Name
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# Traefik routing logs
|
||||
docker logs traefik -f
|
||||
|
||||
# Service logs
|
||||
docker logs gitea -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Timeline Estimate
|
||||
|
||||
If you already have:
|
||||
- Cloudflare domain
|
||||
- Port forwarding access
|
||||
- SSH to TrueNAS
|
||||
|
||||
**Setup time:**
|
||||
- Traefik deployment: 15 minutes
|
||||
- Gitea deployment: 10 minutes
|
||||
- Connect existing stack: 5 minutes
|
||||
- DNS propagation: 5-30 minutes
|
||||
- **Total: ~45 minutes to 1 hour**
|
||||
|
||||
---
|
||||
|
||||
## Next Steps Checklist
|
||||
|
||||
- [ ] Get Cloudflare API token/key
|
||||
- [ ] SSH into TrueNAS
|
||||
- [ ] Verify `/mnt/tank/stacks/` directory structure
|
||||
- [ ] Deploy Traefik stack
|
||||
- [ ] Configure router port forwarding (80, 443, 2222)
|
||||
- [ ] Add DNS records in Cloudflare
|
||||
- [ ] Deploy Gitea stack
|
||||
- [ ] Modify existing stack to connect to Traefik
|
||||
- [ ] Test access to all services via HTTPS
|
||||
- [ ] Configure backups
|
||||
|
||||
---
|
||||
|
||||
## Helpful Documentation
|
||||
|
||||
- [[Traefik Multi-Stack Setup]] - Complete multi-stack guide
|
||||
- [[Quick Reference]] - Common commands
|
||||
- [[Docker Gitea with Traefik]] - Gitea-specific setup details
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Your i7-1065G7 can easily handle Traefik + Gitea + several other services
|
||||
- Expected RAM usage: Traefik (30MB) + Gitea (150MB) = ~200MB total
|
||||
- Cloudflare DNS challenge means SSL works even if ISP blocks port 80
|
||||
- Each stack can use different databases, networks, etc. without conflicts
|
||||
71
Personal/Areas/Servers/TrueNAS/Security TODO.md
Normal file
71
Personal/Areas/Servers/TrueNAS/Security TODO.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Security TODO
|
||||
|
||||
## Future Improvements
|
||||
|
||||
### Investigate Cloudflare Tunnel as Alternative to Port Forwarding
|
||||
|
||||
**Why:**
|
||||
- No ports opened on router (better security)
|
||||
- Cloudflare DDoS protection
|
||||
- Hides home IP address
|
||||
- Works with existing Traefik setup
|
||||
|
||||
**Resources:**
|
||||
- [Cloudflare Tunnel Documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/)
|
||||
- Can work alongside or replace current port forwarding setup
|
||||
|
||||
**Status:** To investigate
|
||||
|
||||
---
|
||||
|
||||
### Look into Pangolin
|
||||
|
||||
**Note:** Research what Pangolin is in context of homelab/self-hosting security
|
||||
|
||||
**Status:** To investigate
|
||||
|
||||
---
|
||||
|
||||
## Current Security Measures
|
||||
|
||||
### Active:
|
||||
- ✅ SSH key-based authentication (password auth disabled)
|
||||
- ✅ Traefik SSL/TLS via Let's Encrypt
|
||||
- ✅ Basic auth on Traefik dashboard
|
||||
- ✅ VPN routing for Servarr stack (via Gluetun)
|
||||
- ✅ Watchtower for automatic container updates
|
||||
|
||||
### Planned:
|
||||
- [ ] Investigate Cloudflare Tunnel
|
||||
- [ ] Research Pangolin
|
||||
- [ ] Add Fail2ban for brute force protection
|
||||
- [ ] Implement Traefik rate limiting middleware
|
||||
- [ ] Set up IP whitelisting for admin interfaces
|
||||
- [ ] Regular security audits of exposed services
|
||||
- [ ] Configure automated backups with encryption
|
||||
|
||||
---
|
||||
|
||||
## Port Forwarding Currently Active
|
||||
|
||||
| Port | Service | Notes |
|
||||
|------|---------|-------|
|
||||
| 80 | Traefik HTTP | Auto-redirects to HTTPS |
|
||||
| 443 | Traefik HTTPS | SSL/TLS encrypted |
|
||||
| 2222 | Gitea SSH | For git operations |
|
||||
|
||||
**Risk Level:** Medium
|
||||
- Publicly exposed services
|
||||
- Mitigated by: SSL, authentication, regular updates
|
||||
|
||||
**Action Items:**
|
||||
- Monitor logs regularly
|
||||
- Keep services updated
|
||||
- Consider Cloudflare Tunnel migration
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [[Traefik Multi-Stack Setup]] - Current setup documentation
|
||||
- [[Integrating Servarr Stack with Traefik]] - VPN-routed services
|
||||
580
Personal/Areas/Servers/TrueNAS/Traefik Multi-Stack Setup.md
Normal file
580
Personal/Areas/Servers/TrueNAS/Traefik Multi-Stack Setup.md
Normal file
@@ -0,0 +1,580 @@
|
||||
# Traefik Multi-Stack Setup
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
**One Traefik instance** serves as the reverse proxy for **multiple independent Docker Compose stacks**.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Traefik (Port 80/443) │
|
||||
│ (Handles SSL & Routing) │
|
||||
└─────────────────┬───────────────────────┘
|
||||
│ traefik_proxy network
|
||||
┌─────────┼─────────┬──────────────┐
|
||||
│ │ │ │
|
||||
┌───▼───┐ ┌──▼────┐ ┌──▼─────┐ ┌───▼────┐
|
||||
│ Gitea │ │ Other │ │ Future │ │ Future │
|
||||
│ Stack │ │ Stack │ │ Stack │ │ Stack │
|
||||
└───────┘ └───────┘ └────────┘ └────────┘
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Each service stack is independent (update/restart without affecting others)
|
||||
- One SSL certificate manager for all services
|
||||
- Easy to add new services
|
||||
- Clean separation of concerns
|
||||
- Each service has its own docker-compose.yml
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
/mnt/tank/stacks/
|
||||
├── traefik/ # Traefik stack
|
||||
│ ├── docker-compose.yml
|
||||
│ ├── traefik.yml
|
||||
│ └── letsencrypt/
|
||||
│ └── acme.json
|
||||
├── gitea/ # Gitea stack
|
||||
│ ├── docker-compose.yml
|
||||
│ └── data/
|
||||
├── servarr/ # Your existing Servarr stack
|
||||
│ ├── docker-compose.yml
|
||||
│ └── data/
|
||||
└── future-service/ # Future additions
|
||||
└── docker-compose.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Deploy Traefik (Once)
|
||||
|
||||
This is the **only** Traefik instance you need.
|
||||
|
||||
### Create Directory
|
||||
|
||||
```bash
|
||||
mkdir -p /mnt/tank/stacks/traefik/letsencrypt
|
||||
cd /mnt/tank/stacks/traefik
|
||||
```
|
||||
|
||||
### Create `traefik.yml`
|
||||
|
||||
```yaml
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: false
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
scheme: https
|
||||
websecure:
|
||||
address: ":443"
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: "unix:///var/run/docker.sock"
|
||||
exposedByDefault: false # Only expose containers with traefik.enable=true
|
||||
network: traefik_proxy # Default network to use
|
||||
|
||||
certificatesResolvers:
|
||||
cloudflare:
|
||||
acme:
|
||||
email: your-email@example.com
|
||||
storage: /letsencrypt/acme.json
|
||||
# Use DNS challenge for Cloudflare (better for wildcard certs)
|
||||
dnsChallenge:
|
||||
provider: cloudflare
|
||||
resolvers:
|
||||
- "1.1.1.1:53"
|
||||
- "1.0.0.1:53"
|
||||
```
|
||||
|
||||
### Create `docker-compose.yml`
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
name: traefik_proxy
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v2.10
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- traefik_proxy
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
# Cloudflare API credentials for DNS challenge
|
||||
- CF_API_EMAIL=your-cloudflare-email@example.com
|
||||
- CF_API_KEY=your-cloudflare-global-api-key
|
||||
# Or use API Token (recommended):
|
||||
# - CF_DNS_API_TOKEN=your-cloudflare-api-token
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./traefik.yml:/traefik.yml:ro
|
||||
- ./letsencrypt:/letsencrypt
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# Dashboard
|
||||
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
|
||||
- "traefik.http.routers.traefik.entrypoints=websecure"
|
||||
- "traefik.http.routers.traefik.tls.certresolver=cloudflare"
|
||||
- "traefik.http.routers.traefik.service=api@internal"
|
||||
# Basic auth for dashboard
|
||||
# Generate: echo $(htpasswd -nb admin yourpassword) | sed -e s/\\$/\\$\\$/g
|
||||
- "traefik.http.routers.traefik.middlewares=traefik-auth"
|
||||
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
```
|
||||
|
||||
### Get Cloudflare API Key
|
||||
|
||||
**Option A: Global API Key (easier but less secure)**
|
||||
1. Cloudflare Dashboard → Profile → API Tokens
|
||||
2. View Global API Key
|
||||
3. Use with `CF_API_EMAIL` and `CF_API_KEY`
|
||||
|
||||
**Option B: API Token (recommended)**
|
||||
1. Cloudflare Dashboard → Profile → API Tokens → Create Token
|
||||
2. Use template: "Edit zone DNS"
|
||||
3. Permissions: Zone → DNS → Edit
|
||||
4. Zone Resources: Include → Specific zone → yourdomain.com
|
||||
5. Use with `CF_DNS_API_TOKEN`
|
||||
|
||||
### Deploy Traefik
|
||||
|
||||
```bash
|
||||
cd /mnt/tank/stacks/traefik
|
||||
docker compose up -d
|
||||
|
||||
# Check logs
|
||||
docker logs traefik -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Connect Gitea to Traefik
|
||||
|
||||
Gitea runs in its **own separate stack**, but connects to Traefik's network.
|
||||
|
||||
### Create `docker-compose.yml` for Gitea
|
||||
|
||||
```bash
|
||||
mkdir -p /mnt/tank/stacks/gitea
|
||||
cd /mnt/tank/stacks/gitea
|
||||
```
|
||||
|
||||
**Key changes from standalone:**
|
||||
- Connects to **external** `traefik_proxy` network
|
||||
- Uses Traefik labels for routing
|
||||
- No exposed ports except SSH (Traefik handles HTTPS)
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true # Uses Traefik's network
|
||||
gitea_internal:
|
||||
driver: bridge # Internal network for Gitea (if needed for DB)
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=sqlite3
|
||||
- GITEA__server__DOMAIN=git.yourdomain.com
|
||||
- GITEA__server__SSH_DOMAIN=git.yourdomain.com
|
||||
- GITEA__server__ROOT_URL=https://git.yourdomain.com
|
||||
- GITEA__server__SSH_PORT=2222
|
||||
- GITEA__server__SSH_LISTEN_PORT=22
|
||||
networks:
|
||||
- traefik_proxy # Connect to Traefik
|
||||
- gitea_internal # Internal network
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "2222:22" # Only SSH needs to be exposed directly
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_proxy"
|
||||
# HTTP/HTTPS routing
|
||||
- "traefik.http.routers.gitea.rule=Host(`git.yourdomain.com`)"
|
||||
- "traefik.http.routers.gitea.entrypoints=websecure"
|
||||
- "traefik.http.routers.gitea.tls.certresolver=cloudflare"
|
||||
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
|
||||
```
|
||||
|
||||
### Deploy Gitea
|
||||
|
||||
```bash
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose up -d
|
||||
|
||||
# Check logs
|
||||
docker logs gitea -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Connect Your Other Stack to Traefik
|
||||
|
||||
For any other service, follow the same pattern:
|
||||
|
||||
### Example: Generic Service
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true # Connect to Traefik's network
|
||||
|
||||
services:
|
||||
your-service:
|
||||
image: your-service-image:latest
|
||||
container_name: your-service
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- traefik_proxy
|
||||
volumes:
|
||||
- ./data:/data
|
||||
# NO ports exposed - Traefik handles routing
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_proxy"
|
||||
- "traefik.http.routers.your-service.rule=Host(`service.yourdomain.com`)"
|
||||
- "traefik.http.routers.your-service.entrypoints=websecure"
|
||||
- "traefik.http.routers.your-service.tls.certresolver=cloudflare"
|
||||
- "traefik.http.services.your-service.loadbalancer.server.port=8080" # Internal port
|
||||
```
|
||||
|
||||
### Deploy Your Service
|
||||
|
||||
```bash
|
||||
cd /mnt/tank/stacks/your-service-name
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
**That's it!** Traefik automatically:
|
||||
- Detects the new container
|
||||
- Creates routes based on labels
|
||||
- Generates SSL certificate
|
||||
- Starts routing traffic
|
||||
|
||||
---
|
||||
|
||||
## Cloudflare DNS Configuration
|
||||
|
||||
For each service, add an A record in Cloudflare:
|
||||
|
||||
### DNS Records
|
||||
|
||||
| Type | Name | Content | Proxy Status |
|
||||
|------|------|---------|--------------|
|
||||
| A | git | Your-Public-IP | DNS Only (gray) |
|
||||
| A | traefik | Your-Public-IP | DNS Only (gray) |
|
||||
| A | service | Your-Public-IP | DNS Only (gray) |
|
||||
|
||||
**Important:** Set to "DNS only" (gray cloud), not proxied (orange cloud), unless you want Cloudflare's proxy in front (requires additional Traefik config).
|
||||
|
||||
---
|
||||
|
||||
## Port Forwarding
|
||||
|
||||
Only forward **once** for Traefik:
|
||||
|
||||
| External Port | Internal Port | Protocol | Service |
|
||||
|--------------|---------------|----------|---------|
|
||||
| 80 | 80 | TCP | HTTP (Traefik) |
|
||||
| 443 | 443 | TCP | HTTPS (Traefik) |
|
||||
| 2222 | 2222 | TCP | SSH (Gitea only) |
|
||||
|
||||
**Additional service-specific ports** (like Gitea SSH on 2222) are forwarded individually.
|
||||
|
||||
---
|
||||
|
||||
## Managing Multiple Stacks
|
||||
|
||||
### Start/Stop Individual Stacks
|
||||
|
||||
```bash
|
||||
# Stop Gitea only (doesn't affect Traefik or other services)
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose down
|
||||
|
||||
# Start Gitea
|
||||
docker compose up -d
|
||||
|
||||
# Restart Gitea
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
### Update Individual Stacks
|
||||
|
||||
```bash
|
||||
# Update just Gitea
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
|
||||
# Update just Traefik
|
||||
cd /mnt/tank/stacks/traefik
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### View All Services
|
||||
|
||||
```bash
|
||||
# See all containers connected to Traefik
|
||||
docker network inspect traefik_proxy
|
||||
|
||||
# See all running containers
|
||||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Adding New Services (Quick Template)
|
||||
|
||||
1. **Create service directory:**
|
||||
```bash
|
||||
mkdir -p /mnt/tank/stacks/new-service
|
||||
cd /mnt/tank/stacks/new-service
|
||||
```
|
||||
|
||||
2. **Create `docker-compose.yml`:**
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true
|
||||
|
||||
services:
|
||||
service-name:
|
||||
image: service-image:latest
|
||||
container_name: service-name
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- traefik_proxy
|
||||
volumes:
|
||||
- ./data:/data
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_proxy"
|
||||
- "traefik.http.routers.service-name.rule=Host(`service.yourdomain.com`)"
|
||||
- "traefik.http.routers.service-name.entrypoints=websecure"
|
||||
- "traefik.http.routers.service-name.tls.certresolver=cloudflare"
|
||||
- "traefik.http.services.service-name.loadbalancer.server.port=INTERNAL_PORT"
|
||||
```
|
||||
|
||||
3. **Add DNS record** in Cloudflare: `service.yourdomain.com → Your-IP`
|
||||
|
||||
4. **Deploy:**
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
5. **Access:** `https://service.yourdomain.com`
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Service with Database
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true
|
||||
internal:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
app:
|
||||
image: app-image:latest
|
||||
networks:
|
||||
- traefik_proxy # For external access
|
||||
- internal # For database access
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_proxy"
|
||||
- "traefik.http.routers.app.rule=Host(`app.yourdomain.com`)"
|
||||
- "traefik.http.routers.app.entrypoints=websecure"
|
||||
- "traefik.http.routers.app.tls.certresolver=cloudflare"
|
||||
- "traefik.http.services.app.loadbalancer.server.port=3000"
|
||||
|
||||
db:
|
||||
image: postgres:15
|
||||
networks:
|
||||
- internal # Only on internal network (not exposed)
|
||||
volumes:
|
||||
- ./db-data:/var/lib/postgresql/data
|
||||
```
|
||||
|
||||
### Multiple Domains for One Service
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.app.rule=Host(`app.yourdomain.com`) || Host(`app2.yourdomain.com`)"
|
||||
- "traefik.http.routers.app.entrypoints=websecure"
|
||||
- "traefik.http.routers.app.tls.certresolver=cloudflare"
|
||||
```
|
||||
|
||||
### Service with Path Prefix
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.app.rule=Host(`yourdomain.com`) && PathPrefix(`/app`)"
|
||||
- "traefik.http.routers.app.entrypoints=websecure"
|
||||
- "traefik.http.routers.app.tls.certresolver=cloudflare"
|
||||
- "traefik.http.middlewares.app-stripprefix.stripprefix.prefixes=/app"
|
||||
- "traefik.http.routers.app.middlewares=app-stripprefix"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Multi-Stack Setup
|
||||
|
||||
### Service Not Accessible
|
||||
|
||||
```bash
|
||||
# Check if container is on traefik_proxy network
|
||||
docker network inspect traefik_proxy
|
||||
|
||||
# Check Traefik logs for routing issues
|
||||
docker logs traefik | grep -i error
|
||||
|
||||
# Verify DNS resolves correctly
|
||||
nslookup service.yourdomain.com
|
||||
|
||||
# Check if Traefik sees the service
|
||||
docker exec traefik wget -O- http://localhost:8080/api/http/routers | grep service-name
|
||||
```
|
||||
|
||||
### SSL Certificate Issues
|
||||
|
||||
```bash
|
||||
# Check Traefik logs for ACME errors
|
||||
docker logs traefik | grep -i acme
|
||||
|
||||
# Verify Cloudflare credentials are correct
|
||||
docker exec traefik env | grep CF_
|
||||
|
||||
# Delete acme.json to force renewal (last resort)
|
||||
docker compose down
|
||||
rm letsencrypt/acme.json
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Network Conflicts
|
||||
|
||||
```bash
|
||||
# List all networks
|
||||
docker network ls
|
||||
|
||||
# Inspect traefik_proxy network
|
||||
docker network inspect traefik_proxy
|
||||
|
||||
# Recreate network if needed
|
||||
docker network rm traefik_proxy
|
||||
cd /mnt/[pool]/docker/traefik
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stack Independence Benefits
|
||||
|
||||
✅ **Update one service without affecting others**
|
||||
```bash
|
||||
cd /mnt/tank/stacks/gitea
|
||||
docker compose pull && docker compose up -d
|
||||
# Other services keep running
|
||||
```
|
||||
|
||||
✅ **Restart one service without downtime for others**
|
||||
```bash
|
||||
docker restart gitea
|
||||
# Traefik and other services unaffected
|
||||
```
|
||||
|
||||
✅ **Remove a service cleanly**
|
||||
```bash
|
||||
cd /mnt/tank/stacks/old-service
|
||||
docker compose down
|
||||
rm -rf /mnt/tank/stacks/old-service
|
||||
# Done! No leftover configs in other stacks
|
||||
```
|
||||
|
||||
✅ **Easy backups per service**
|
||||
```bash
|
||||
tar -czf gitea-backup.tar.gz /mnt/tank/stacks/gitea/
|
||||
tar -czf servarr-backup.tar.gz /mnt/tank/stacks/servarr/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [ ] Deploy Traefik (one time)
|
||||
- [ ] Get Cloudflare API credentials
|
||||
- [ ] Configure DNS records for services
|
||||
- [ ] Deploy Gitea stack
|
||||
- [ ] Connect your existing stack to Traefik
|
||||
- [ ] Test accessing all services via HTTPS
|
||||
- [ ] Set up automated backups per stack
|
||||
|
||||
---
|
||||
|
||||
## Example Full Setup
|
||||
|
||||
```
|
||||
/mnt/tank/stacks/
|
||||
├── traefik/
|
||||
│ ├── docker-compose.yml # Traefik
|
||||
│ ├── traefik.yml
|
||||
│ └── letsencrypt/
|
||||
├── gitea/
|
||||
│ ├── docker-compose.yml # Gitea stack
|
||||
│ └── data/
|
||||
├── servarr/
|
||||
│ ├── docker-compose.yml # Servarr stack (your existing)
|
||||
│ └── ...
|
||||
├── nextcloud/
|
||||
│ ├── docker-compose.yml # Nextcloud stack
|
||||
│ ├── app-data/
|
||||
│ └── db-data/
|
||||
└── vaultwarden/
|
||||
├── docker-compose.yml # Vaultwarden stack
|
||||
└── data/
|
||||
```
|
||||
|
||||
Each stack is independent, but all route through Traefik! 🎉
|
||||
72
Personal/Areas/Servers/TrueNAS/TrueNAS.md
Normal file
72
Personal/Areas/Servers/TrueNAS/TrueNAS.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# TrueNAS Server
|
||||
|
||||
## Overview
|
||||
|
||||
Documentation for TrueNAS home server setup, configuration, and services.
|
||||
|
||||
## System Information
|
||||
|
||||
- **Type:** TrueNAS Scale
|
||||
- **Hardware:**
|
||||
- CPU: Intel Core i7-1065G7 (4 cores, 8 threads @ 1.30GHz base)
|
||||
- RAM: 16GB
|
||||
- Form Factor: Laptop
|
||||
- **Storage Configuration:**
|
||||
- Pool: `tank`
|
||||
- Docker Stacks: `/mnt/tank/stacks/`
|
||||
- Configs: `/mnt/tank/configs/`
|
||||
- Media: `/mnt/tank/media/`
|
||||
- **Timezone:** Europe/Amsterdam
|
||||
- **Network:** TBD
|
||||
|
||||
## Services & Applications
|
||||
|
||||
**Currently Deployed:**
|
||||
- Servarr Stack (VPN-routed media automation) - See [[servarr.yaml]]
|
||||
- Gluetun (ProtonVPN), qBittorrent, Sonarr, Radarr, Lidarr, Prowlarr, Bazarr, Recyclarr, Dozzle, Watchtower
|
||||
|
||||
**Start Here:**
|
||||
- [[Recommended Setup]] - ⭐ Your complete setup plan (Traefik + Gitea + existing stack)
|
||||
|
||||
**Detailed Guides:**
|
||||
- [[Traefik Multi-Stack Setup]] - One Traefik instance for multiple service stacks
|
||||
- [[Integrating Servarr Stack with Traefik]] - How to connect your existing Servarr stack
|
||||
- [[Docker Gitea with Traefik]] - Docker deployment with Traefik reverse proxy
|
||||
- [[Gitea Setup]] - Alternative: TrueNAS Apps installation (not using this)
|
||||
- [[Git Server Options]] - Comparison of all git server options
|
||||
|
||||
**Reference:**
|
||||
- [[Quick Reference]] - Common commands and troubleshooting
|
||||
- [[VS Code SSH Setup]] - Configure VS Code for remote editing
|
||||
- [[Security TODO]] - Future security improvements and research
|
||||
|
||||
## Configuration
|
||||
|
||||
### Datasets
|
||||
|
||||
|
||||
### Shares
|
||||
|
||||
|
||||
### Snapshots & Replication
|
||||
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Backup Strategy
|
||||
|
||||
|
||||
### Update Schedule
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
- [TrueNAS Documentation](https://www.truenas.com/docs/)
|
||||
- [TrueNAS Community Forums](https://www.truenas.com/community/)
|
||||
- [Traefik Documentation](https://doc.traefik.io/traefik/)
|
||||
- [Gitea Documentation](https://docs.gitea.io/)
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
6XdKFJCp3hYPuKXD6AgP0m5KbxjueQzB
|
||||
405
Personal/Areas/Servers/TrueNAS/VS Code SSH Setup.md
Normal file
405
Personal/Areas/Servers/TrueNAS/VS Code SSH Setup.md
Normal file
@@ -0,0 +1,405 @@
|
||||
# VS Code SSH Setup for TrueNAS
|
||||
|
||||
## Overview
|
||||
|
||||
Configure VS Code to SSH into your TrueNAS server for easy file editing and terminal access.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **VS Code installed** on your local machine
|
||||
2. **Remote - SSH extension** installed in VS Code
|
||||
3. **SSH access enabled** on TrueNAS
|
||||
4. **TrueNAS IP address** or hostname
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Install VS Code Extension
|
||||
|
||||
### Install Remote - SSH Extension
|
||||
|
||||
1. Open VS Code
|
||||
2. Click Extensions icon (or `Ctrl+Shift+X`)
|
||||
3. Search for: **Remote - SSH**
|
||||
4. Install the extension by Microsoft
|
||||
5. Reload VS Code if prompted
|
||||
|
||||
**Extension ID:** `ms-vscode-remote.remote-ssh`
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Enable SSH on TrueNAS (if not already enabled)
|
||||
|
||||
### TrueNAS Scale
|
||||
|
||||
1. Navigate to **System Settings → Services**
|
||||
2. Find **SSH** service
|
||||
3. Click **Edit** (pencil icon)
|
||||
4. Configure:
|
||||
- ☑ **Allow Password Authentication** (initially, we'll use keys later)
|
||||
- ☑ **Allow TCP Forwarding**
|
||||
- Port: **22** (default)
|
||||
5. Click **Save**
|
||||
6. **Start** the SSH service
|
||||
7. ☑ **Start Automatically** (enable)
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Find Your TrueNAS Connection Details
|
||||
|
||||
### Get TrueNAS IP Address
|
||||
|
||||
**Option A: From TrueNAS UI**
|
||||
- Dashboard → Top right shows IP address
|
||||
|
||||
**Option B: From Shell**
|
||||
```bash
|
||||
ip addr show | grep inet
|
||||
```
|
||||
|
||||
### Get Your Username
|
||||
|
||||
**Default admin user:** `admin`
|
||||
|
||||
Or check: **Credentials → Local Users**
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Generate SSH Key (Recommended)
|
||||
|
||||
**On your local Windows machine (WSL or PowerShell):**
|
||||
|
||||
### Using WSL (Recommended)
|
||||
|
||||
```bash
|
||||
# Generate SSH key
|
||||
ssh-keygen -t ed25519 -C "truenas-access"
|
||||
|
||||
# Default location: ~/.ssh/id_ed25519
|
||||
# Press Enter to accept
|
||||
# Enter passphrase (optional but recommended)
|
||||
|
||||
# Copy public key to TrueNAS
|
||||
ssh-copy-id admin@truenas-ip
|
||||
|
||||
# Or manually copy:
|
||||
cat ~/.ssh/id_ed25519.pub
|
||||
# Then paste into TrueNAS UI
|
||||
```
|
||||
|
||||
### Using PowerShell (Alternative)
|
||||
|
||||
```powershell
|
||||
# Generate SSH key
|
||||
ssh-keygen -t ed25519 -C "truenas-access"
|
||||
|
||||
# Location: C:\Users\Vince\.ssh\id_ed25519
|
||||
# Copy public key
|
||||
Get-Content C:\Users\Vince\.ssh\id_ed25519.pub
|
||||
```
|
||||
|
||||
### Add Public Key to TrueNAS
|
||||
|
||||
1. TrueNAS UI → **Credentials → Local Users**
|
||||
2. Click **Edit** on your user (admin)
|
||||
3. Scroll to **SSH Public Key**
|
||||
4. Paste your public key
|
||||
5. Click **Save**
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Configure SSH Config File
|
||||
|
||||
Create/edit SSH config for easy connections.
|
||||
|
||||
### Location
|
||||
|
||||
**WSL:** `~/.ssh/config`
|
||||
**Windows:** `C:\Users\Vince\.ssh\config`
|
||||
|
||||
### Add TrueNAS Configuration
|
||||
|
||||
```bash
|
||||
Host truenas
|
||||
HostName 192.168.1.XXX # Your TrueNAS IP
|
||||
User admin # Your TrueNAS username
|
||||
Port 22
|
||||
IdentityFile ~/.ssh/id_ed25519 # Path to your SSH key
|
||||
ForwardAgent yes
|
||||
ServerAliveInterval 60
|
||||
ServerAliveCountMax 3
|
||||
|
||||
# Optional: Shorter alias
|
||||
Host nas
|
||||
HostName 192.168.1.XXX
|
||||
User admin
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
```
|
||||
|
||||
**Replace:** `192.168.1.XXX` with your actual TrueNAS IP
|
||||
|
||||
### Test SSH Connection
|
||||
|
||||
```bash
|
||||
ssh truenas
|
||||
# or
|
||||
ssh nas
|
||||
```
|
||||
|
||||
Should connect without password!
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Connect VS Code to TrueNAS
|
||||
|
||||
### Method 1: Using Command Palette
|
||||
|
||||
1. Open VS Code
|
||||
2. Press `Ctrl+Shift+P` (or `F1`)
|
||||
3. Type: **Remote-SSH: Connect to Host**
|
||||
4. Select **truenas** (or **nas**) from the list
|
||||
- Or type: `admin@truenas-ip` manually
|
||||
5. Select platform: **Linux**
|
||||
6. VS Code will connect and install VS Code Server on TrueNAS
|
||||
7. Wait for connection to complete
|
||||
|
||||
### Method 2: Using SSH Targets
|
||||
|
||||
1. Click **Remote Explorer** icon in sidebar
|
||||
2. Under **SSH Targets**, you'll see configured hosts
|
||||
3. Click **→** (Connect) next to **truenas**
|
||||
|
||||
### First Connection
|
||||
|
||||
- VS Code will install **VS Code Server** on TrueNAS (~100MB)
|
||||
- This is a one-time setup
|
||||
- May take 1-2 minutes
|
||||
- You'll see progress in bottom right
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Navigate to Your Stacks Directory
|
||||
|
||||
Once connected:
|
||||
|
||||
1. **File → Open Folder**
|
||||
2. Type: `/mnt/tank/stacks`
|
||||
3. Click **OK**
|
||||
4. VS Code now shows your stacks directory in explorer!
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Install Helpful Extensions (Remote)
|
||||
|
||||
Once connected to TrueNAS, install these extensions **on the remote**:
|
||||
|
||||
### Recommended Extensions
|
||||
|
||||
1. **Docker** (`ms-azuretools.vscode-docker`)
|
||||
- Syntax highlighting for docker-compose files
|
||||
- Docker commands integration
|
||||
|
||||
2. **YAML** (`redhat.vscode-yaml`)
|
||||
- YAML syntax validation
|
||||
- Auto-completion
|
||||
|
||||
3. **Remote - SSH: Editing Configuration Files** (automatic)
|
||||
- Edit SSH config directly from VS Code
|
||||
|
||||
### Install Extensions on Remote
|
||||
|
||||
1. Click **Extensions** icon
|
||||
2. Search for extension
|
||||
3. Click **Install in SSH: truenas**
|
||||
4. Extensions install on the TrueNAS server
|
||||
|
||||
---
|
||||
|
||||
## Usage Tips
|
||||
|
||||
### Open Terminal in VS Code
|
||||
|
||||
- **Terminal → New Terminal** (`` Ctrl+` ``)
|
||||
- Opens bash terminal directly on TrueNAS
|
||||
- Already in the folder you have open
|
||||
|
||||
### Edit docker-compose Files
|
||||
|
||||
1. Navigate to `/mnt/tank/stacks/traefik/`
|
||||
2. Edit `docker-compose.yml`
|
||||
3. Syntax highlighting and validation included
|
||||
4. Save with `Ctrl+S`
|
||||
|
||||
### Run Docker Commands
|
||||
|
||||
```bash
|
||||
# In VS Code terminal
|
||||
cd /mnt/tank/stacks/traefik
|
||||
docker compose up -d
|
||||
docker logs traefik -f
|
||||
```
|
||||
|
||||
### Multiple Folders
|
||||
|
||||
Open workspace with multiple stack directories:
|
||||
1. **File → Add Folder to Workspace**
|
||||
2. Add `/mnt/tank/stacks/traefik`
|
||||
3. Add `/mnt/tank/stacks/gitea`
|
||||
4. Add `/mnt/tank/stacks/servarr`
|
||||
5. **File → Save Workspace As** → `truenas-stacks.code-workspace`
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Refused
|
||||
|
||||
```bash
|
||||
# Check SSH service is running on TrueNAS
|
||||
# TrueNAS UI → System → Services → SSH → Running
|
||||
|
||||
# Test from terminal
|
||||
ssh admin@truenas-ip
|
||||
```
|
||||
|
||||
### Permission Denied (publickey)
|
||||
|
||||
```bash
|
||||
# Verify public key is added to TrueNAS
|
||||
# TrueNAS UI → Credentials → Local Users → Edit → SSH Public Key
|
||||
|
||||
# Or enable password authentication temporarily
|
||||
# TrueNAS UI → System → Services → SSH → Edit
|
||||
# ☑ Allow Password Authentication
|
||||
```
|
||||
|
||||
### VS Code Server Installation Fails
|
||||
|
||||
```bash
|
||||
# SSH into TrueNAS manually
|
||||
ssh truenas
|
||||
|
||||
# Check available disk space
|
||||
df -h
|
||||
|
||||
# VS Code Server needs ~100MB in home directory
|
||||
# Clear space if needed
|
||||
```
|
||||
|
||||
### "Could not establish connection"
|
||||
|
||||
```bash
|
||||
# Check VS Code settings
|
||||
# Ctrl+, → Search "remote.SSH.path"
|
||||
# Should point to ssh executable
|
||||
|
||||
# Windows: C:\Windows\System32\OpenSSH\ssh.exe
|
||||
# WSL: /usr/bin/ssh
|
||||
```
|
||||
|
||||
### Wrong Platform Detected
|
||||
|
||||
If VS Code thinks TrueNAS is Windows/Mac:
|
||||
1. `Ctrl+Shift+P`
|
||||
2. **Remote-SSH: Settings**
|
||||
3. Add to `settings.json`:
|
||||
```json
|
||||
"remote.SSH.remotePlatform": {
|
||||
"truenas": "linux"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Disable Password Authentication (After Key Setup)
|
||||
|
||||
Once SSH keys are working:
|
||||
|
||||
1. TrueNAS UI → **System → Services → SSH → Edit**
|
||||
2. ☐ **Allow Password Authentication** (uncheck)
|
||||
3. ☑ **Login as Root with Password** (uncheck)
|
||||
4. Click **Save**
|
||||
|
||||
Now only SSH key authentication is allowed.
|
||||
|
||||
### Use SSH Key Passphrase
|
||||
|
||||
When generating keys, add a passphrase:
|
||||
```bash
|
||||
ssh-keygen -t ed25519 -C "truenas-access"
|
||||
# Enter passphrase when prompted
|
||||
```
|
||||
|
||||
Use `ssh-agent` to avoid typing passphrase repeatedly:
|
||||
```bash
|
||||
# Start ssh-agent (WSL)
|
||||
eval "$(ssh-agent -s)"
|
||||
|
||||
# Add key
|
||||
ssh-add ~/.ssh/id_ed25519
|
||||
|
||||
# Enter passphrase once
|
||||
# Key is cached for session
|
||||
```
|
||||
|
||||
### Firewall Considerations
|
||||
|
||||
If accessing TrueNAS from outside your network:
|
||||
- **Don't expose SSH (port 22) directly to internet**
|
||||
- Use VPN (Tailscale, Wireguard) instead
|
||||
- Or use SSH tunneling through a bastion host
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Connect to TrueNAS
|
||||
|
||||
```bash
|
||||
# Command line
|
||||
ssh truenas
|
||||
|
||||
# VS Code
|
||||
Ctrl+Shift+P → Remote-SSH: Connect to Host → truenas
|
||||
```
|
||||
|
||||
### Common Paths
|
||||
|
||||
- **Stacks:** `/mnt/tank/stacks/`
|
||||
- **Configs:** `/mnt/tank/configs/`
|
||||
- **Media:** `/mnt/tank/media/`
|
||||
|
||||
### Useful VS Code Shortcuts
|
||||
|
||||
- **Open Terminal:** `` Ctrl+` ``
|
||||
- **Command Palette:** `Ctrl+Shift+P`
|
||||
- **Open Folder:** `Ctrl+K Ctrl+O`
|
||||
- **Search Files:** `Ctrl+P`
|
||||
- **Save:** `Ctrl+S`
|
||||
- **Close Remote:** Click **SSH: truenas** in bottom left → **Close Remote Connection**
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [ ] Install Remote - SSH extension in VS Code
|
||||
- [ ] Enable SSH service on TrueNAS
|
||||
- [ ] Generate SSH key on local machine
|
||||
- [ ] Add public key to TrueNAS
|
||||
- [ ] Configure ~/.ssh/config with TrueNAS host
|
||||
- [ ] Test SSH connection from terminal
|
||||
- [ ] Connect VS Code to TrueNAS
|
||||
- [ ] Open `/mnt/tank/stacks` folder in VS Code
|
||||
- [ ] Install Docker and YAML extensions (remote)
|
||||
- [ ] Disable password authentication (after key setup)
|
||||
- [ ] Create workspace for multiple stack folders
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [VS Code Remote - SSH Documentation](https://code.visualstudio.com/docs/remote/ssh)
|
||||
- [TrueNAS Scale SSH Documentation](https://www.truenas.com/docs/scale/scaletutorials/systemsettings/services/configuringsshservice/)
|
||||
141
Personal/Areas/Servers/TrueNAS/servarr.yaml
Normal file
141
Personal/Areas/Servers/TrueNAS/servarr.yaml
Normal file
@@ -0,0 +1,141 @@
|
||||
services:
|
||||
gluetun:
|
||||
image: qmcgaw/gluetun:latest
|
||||
container_name: gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
environment:
|
||||
- VPN_SERVICE_PROVIDER=protonvpn
|
||||
- VPN_TYPE=wireguard
|
||||
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
|
||||
- SERVER_COUNTRIES=Netherlands
|
||||
- TZ=Europe/Amsterdam
|
||||
volumes:
|
||||
- /mnt/tank/configs/gluetun:/gluetun
|
||||
- /mnt/tank/configs/gluetun-tmp:/tmp/gluetun
|
||||
ports:
|
||||
- 8080:8080 # qBittorrent WebUI
|
||||
- 7878:7878 # Radarr
|
||||
- 8686:8686 # Lidarr
|
||||
- 8989:8989 # Sonarr
|
||||
- 9696:9696 # Prowlarr
|
||||
- 6767:6767 # Bazarr
|
||||
restart: unless-stopped
|
||||
qbittorrent:
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
container_name: qbittorrent
|
||||
environment:
|
||||
- PUID=568
|
||||
- PGID=568
|
||||
- TZ=Europe/Amsterdam
|
||||
- WEBUI_PORT=8080
|
||||
volumes:
|
||||
- /mnt/tank/configs/qbittorrent:/config
|
||||
- /mnt/tank/media:/media
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
- gluetun
|
||||
restart: unless-stopped
|
||||
prowlarr:
|
||||
image: lscr.io/linuxserver/prowlarr:latest
|
||||
container_name: prowlarr
|
||||
environment:
|
||||
- PUID=568
|
||||
- PGID=568
|
||||
- TZ=Europe/Amsterdam
|
||||
volumes:
|
||||
- /mnt/tank/configs/prowlarr:/config
|
||||
- /mnt/tank/media:/media
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
- gluetun
|
||||
restart: unless-stopped
|
||||
lidarr:
|
||||
image: lscr.io/linuxserver/lidarr:latest
|
||||
container_name: lidarr
|
||||
environment:
|
||||
- PUID=568
|
||||
- PGID=568
|
||||
- TZ=Europe/Amsterdam
|
||||
volumes:
|
||||
- /mnt/tank/configs/lidarr:/config
|
||||
- /mnt/tank/media:/media
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
- gluetun
|
||||
restart: unless-stopped
|
||||
radarr:
|
||||
image: lscr.io/linuxserver/radarr:latest
|
||||
container_name: radarr
|
||||
environment:
|
||||
- PUID=568
|
||||
- PGID=568
|
||||
- TZ=Europe/Amsterdam
|
||||
volumes:
|
||||
- /mnt/tank/configs/radarr:/config
|
||||
- /mnt/tank/media:/media
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
- gluetun
|
||||
restart: unless-stopped
|
||||
sonarr:
|
||||
image: lscr.io/linuxserver/sonarr:latest
|
||||
container_name: sonarr
|
||||
environment:
|
||||
- PUID=568
|
||||
- PGID=568
|
||||
- TZ=Europe/Amsterdam
|
||||
volumes:
|
||||
- /mnt/tank/configs/sonarr:/config
|
||||
- /mnt/tank/media:/media
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
- gluetun
|
||||
restart: unless-stopped
|
||||
bazarr:
|
||||
image: lscr.io/linuxserver/bazarr:latest
|
||||
container_name: bazarr
|
||||
environment:
|
||||
- PUID=568
|
||||
- PGID=568
|
||||
- TZ=Europe/Amsterdam
|
||||
volumes:
|
||||
- /mnt/tank/configs/bazarr:/config
|
||||
- /mnt/tank/media:/media
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
- gluetun
|
||||
- sonarr
|
||||
- radarr
|
||||
restart: unless-stopped
|
||||
recyclarr:
|
||||
image: ghcr.io/recyclarr/recyclarr:latest
|
||||
container_name: recyclarr
|
||||
user: 568:568
|
||||
environment:
|
||||
- CRON_SCHEDULE=0 0 * * *
|
||||
- TZ=Europe/Amsterdam
|
||||
volumes:
|
||||
- /mnt/tank/configs/recyclarr:/config
|
||||
network_mode: service:gluetun
|
||||
depends_on:
|
||||
- gluetun
|
||||
restart: unless-stopped
|
||||
dozzle:
|
||||
image: amir20/dozzle:latest
|
||||
container_name: dozzle
|
||||
ports:
|
||||
- 9999:8080 # Access Dozzle UI at http://<host-ip>:9999
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
restart: unless-stopped
|
||||
watchtower:
|
||||
image: containrrr/watchtower:latest
|
||||
container_name: watchtower
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- TZ=Europe/Amsterdam
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
restart: unless-stopped
|
||||
networks: {}
|
||||
Reference in New Issue
Block a user