Difficulty: Intermediate | Time: 30-45 minutes | Method: Docker/Container Station
Deploy OpenCodeHub on your Network Attached Storage (NAS) device. This is perfect for small teams, personal use, or as a private Git server at home. Works on Synology DSM, TrueNAS SCALE, QNAP QTS, and any NAS supporting Docker.
| NAS Type | Minimum Requirements |
|---|---|
| Synology | DSM 7.0+, 4GB RAM (8GB recommended), x86_64 or ARM64 (better performance on x86_64) |
| TrueNAS SCALE | 8GB RAM, 2 CPU cores, 40GB free space |
| QNAP | QTS 5.0+, 4GB RAM, Container Station installed |
| Generic | Docker/Podman support, 4GB RAM, 2 CPU cores |
- A domain with DDNS (Dynamic DNS) configured (e.g.,
git.yourddns.net) OR local network access only - Port forwarding configured on your router (if accessing externally):
80→ NAS:80443→ NAS:4432222→ NAS:2222 (for SSH Git, optional)
- Open Package Center
- Search for Container Manager (DSM 7.2+) or Docker (older DSM)
- Click Install
-
Open Control Panel → Shared Folder → Create
-
Create these folders:
opencodehub/repos— Git repositoriesopencodehub/storage— File uploadsopencodehub/ssh— SSH host keysopencodehub/cache— Application cacheopencodehub/postgres— PostgreSQL dataopencodehub/redis— Redis data
-
Set permissions:
- Right-click each folder → Edit → Permissions
- Grant Read/Write to your admin user and the
Dockersystem group
-
Open Container Manager → Image → Add → Add from URL
-
Image name:
postgres -
Tag:
16-alpine -
Click Add
-
Go to Container → Create
-
Select
postgres:16-alpine -
Configuration:
- Container name:
opencodehub-postgres - Enable auto-restart: Yes
- Network: Use the same bridge network as other containers
- Environment variables:
POSTGRES_USER=opencodehub POSTGRES_PASSWORD=<generate-strong-password> POSTGRES_DB=opencodehub - Volume settings:
/volume1/opencodehub/postgres → /var/lib/postgresql/data - Port settings:
Local port: 5432 → Container port: 5432
- Container name:
-
Click Done
ssh admin@your-synology-ip
sudo -i
docker run -d \
--name opencodehub-postgres \
--restart unless-stopped \
-e POSTGRES_USER=opencodehub \
-e POSTGRES_PASSWORD=YOUR_PASSWORD \
-e POSTGRES_DB=opencodehub \
-v /volume1/opencodehub/postgres:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:16-alpineUsing Container Manager:
- Pull
redis:7-alpine - Create container:
- Name:
opencodehub-redis - Environment:
REDIS_PASSWORD=<strong-password> - Command:
redis-server --appendonly yes --requirepass YOUR_PASSWORD - Volume:
/volume1/opencodehub/redis → /data - Port:
6379→6379
- Name:
Or via SSH:
docker run -d \
--name opencodehub-redis \
--restart unless-stopped \
-v /volume1/opencodehub/redis:/data \
-p 6379:6379 \
redis:7-alpine \
redis-server --appendonly yes --requirepass YOUR_PASSWORDIf using the published Docker image:
docker run -d \
--name opencodehub \
--restart unless-stopped \
--link opencodehub-postgres:postgres \
--link opencodehub-redis:redis \
-p 4321:4321 \
-p 2222:2222 \
-e NODE_ENV=production \
-e DATABASE_URL=postgresql://opencodehub:POSTGRES_PASS@host.docker.internal:5432/opencodehub \
-e REDIS_URL=redis://:REDIS_PASS@host.docker.internal:6379 \
-e JWT_SECRET=$(openssl rand -hex 32) \
-e SESSION_SECRET=$(openssl rand -hex 32) \
-e INTERNAL_HOOK_SECRET=$(openssl rand -hex 32) \
-e CRON_SECRET=$(openssl rand -hex 32) \
-e RUNNER_SECRET=$(openssl rand -hex 32) \
-e WORKFLOW_SECRET_ENCRYPTION_KEY=$(openssl rand -hex 32) \
-e SITE_URL=https://git.yourddns.net \
-e STORAGE_TYPE=local \
-e STORAGE_PATH=/data/storage \
-e REPOS_PATH=/data/repos \
-e SSH_HOST_KEY_PATH=/data/ssh/host_key \
-v /volume1/opencodehub/repos:/data/repos \
-v /volume1/opencodehub/storage:/data/storage \
-v /volume1/opencodehub/ssh:/data/ssh \
-v /volume1/opencodehub/cache:/data/cache \
opencodehub/opencodehub:latestNote: On Synology,
host.docker.internalmay not work. Use your NAS IP address instead (e.g.,192.168.1.100).
- In Container Manager → Project (Docker Compose):
version: '3.8'
services:
app:
build:
context: /volume1/docker/OpenCodeHub
dockerfile: Dockerfile
container_name: opencodehub
restart: unless-stopped
ports:
- "4321:4321"
- "2222:2222"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://opencodehub:YOUR_PASS@postgres:5432/opencodehub
- REDIS_URL=redis://:YOUR_PASS@redis:6379
- JWT_SECRET=YOUR_SECRET
- SESSION_SECRET=YOUR_SECRET
- INTERNAL_HOOK_SECRET=YOUR_SECRET
- CRON_SECRET=YOUR_SECRET
- RUNNER_SECRET=YOUR_SECRET
- WORKFLOW_SECRET_ENCRYPTION_KEY=YOUR_SECRET
- SITE_URL=https://git.yourddns.net
- STORAGE_TYPE=local
- STORAGE_PATH=/data/storage
- REPOS_PATH=/data/repos
- SSH_HOST_KEY_PATH=/data/ssh/host_key
volumes:
- /volume1/opencodehub/repos:/data/repos
- /volume1/opencodehub/storage:/data/storage
- /volume1/opencodehub/ssh:/data/ssh
- /volume1/opencodehub/cache:/data/cache
depends_on:
- postgres
- redis
networks:
- och-net
postgres:
image: postgres:16-alpine
container_name: opencodehub-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=opencodehub
- POSTGRES_PASSWORD=YOUR_PASS
- POSTGRES_DB=opencodehub
volumes:
- /volume1/opencodehub/postgres:/var/lib/postgresql/data
networks:
- och-net
redis:
image: redis:7-alpine
container_name: opencodehub-redis
restart: unless-stopped
command: redis-server --appendonly yes --requirepass YOUR_PASS
volumes:
- /volume1/opencodehub/redis:/data
networks:
- och-net
networks:
och-net:
driver: bridge- Save this as
docker-compose.ymlin/volume1/docker/OpenCodeHub/ - Clone the repo to that folder first:
cd /volume1/docker git clone https://github.com/swadhinbiswas/OpencodeHub.git - In Container Manager → Project → Create
- Select the path
/volume1/docker/OpenCodeHub - Click Create
- Control Panel → Login Portal → Advanced → Reverse Proxy
- Click Create
- General:
- Source:
- Protocol: HTTPS
- Hostname:
git.yourddns.net - Port: 443
- Destination:
- Protocol: HTTP
- Hostname:
localhost - Port: 4321
- Source:
- Custom Header → Create → WebSocket
- Header name:
Upgrade - Value:
$http_upgrade - Header name:
Connection - Value:
upgrade
- Header name:
- Click Save
-
Control Panel → Security → Certificate
-
Click Add → Add a new certificate
-
Select Get a certificate from Let's Encrypt
-
Domain name:
git.yourddns.net -
Email: your-email@example.com
-
Click Apply
-
After issuance, go to Configure and assign the certificate to:
git.yourddns.net:443(your reverse proxy)
TrueNAS SCALE has native Kubernetes support with Helm charts, but Docker is easier via Apps (Docker Compose).
- Go to Storage → Pools → Your pool → Add Dataset
- Create a parent dataset:
opencodehub - Under it, create:
reposstoragesshcachepostgresredis
- Go to Apps → Discover Apps → Custom App
- Enable Advanced Mode
- Enter this Docker Compose:
version: '3.8'
services:
app:
image: opencodehub/opencodehub:latest
container_name: opencodehub
restart: unless-stopped
ports:
- "4321:4321"
- "2222:2222"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://opencodehub:YOUR_PASS@postgres:5432/opencodehub
- REDIS_URL=redis://:YOUR_PASS@redis:6379
- JWT_SECRET=YOUR_SECRET
- SESSION_SECRET=YOUR_SECRET
- INTERNAL_HOOK_SECRET=YOUR_SECRET
- CRON_SECRET=YOUR_SECRET
- RUNNER_SECRET=YOUR_SECRET
- WORKFLOW_SECRET_ENCRYPTION_KEY=YOUR_SECRET
- SITE_URL=https://git.yourdomain.com
- STORAGE_TYPE=local
- STORAGE_PATH=/data/storage
- REPOS_PATH=/data/repos
- SSH_HOST_KEY_PATH=/data/ssh/host_key
volumes:
- /mnt/YOURPOOL/opencodehub/repos:/data/repos
- /mnt/YOURPOOL/opencodehub/storage:/data/storage
- /mnt/YOURPOOL/opencodehub/ssh:/data/ssh
- /mnt/YOURPOOL/opencodehub/cache:/data/cache
depends_on:
- postgres
- redis
networks:
- och-net
postgres:
image: postgres:16-alpine
container_name: opencodehub-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=opencodehub
- POSTGRES_PASSWORD=YOUR_PASS
- POSTGRES_DB=opencodehub
volumes:
- /mnt/YOURPOOL/opencodehub/postgres:/var/lib/postgresql/data
networks:
- och-net
redis:
image: redis:7-alpine
container_name: opencodehub-redis
restart: unless-stopped
command: redis-server --appendonly yes --requirepass YOUR_PASS
volumes:
- /mnt/YOURPOOL/opencodehub/redis:/data
networks:
- och-net
networks:
och-net:
driver: bridgeReplace
YOURPOOLwith your actual pool name andYOUR_PASS/YOUR_SECRETwith your values.
- Click Save
- TrueNAS will deploy all containers
- System → General → GUI SSL Certificate
- Or use Apps → Certificates for app-specific SSL
- For external access, use TrueNAS's built-in ACME (Let's Encrypt) or upload your own certificate
Install Nginx Proxy Manager from the TrueNAS Apps catalog:
- Apps → Discover Apps → Search "Nginx Proxy Manager"
- Install with default settings
- Access Nginx Proxy Manager at
your-nas-ip:81 - Add Proxy Host:
- Domain Names:
git.yourdomain.com - Forward Hostname/IP:
opencodehub - Forward Port:
4321 - Enable Block Common Exploits
- SSL: Request a new SSL certificate from Let's Encrypt
- Enable Force SSL and HTTP/2 Support
- Domain Names:
- Open App Center
- Search for Container Station
- Click Install
- Open File Station
- Create folder:
opencodehub - Inside it create:
repos,storage,ssh,cache,postgres,redis
- Container Station → Networks → Create
- Name:
opencodehub-network - Driver: Bridge
- Create → Search Docker Hub →
postgres:16-alpine - Click Install
- Configuration:
- Name:
opencodehub-postgres - Network:
opencodehub-network - Environment:
POSTGRES_USER=opencodehub POSTGRES_PASSWORD=<password> POSTGRES_DB=opencodehub - Shared Folders:
/share/Container/opencodehub/postgres → /var/lib/postgresql/data - Port:
5432
- Name:
- Search and install
redis:7-alpine - Name:
opencodehub-redis - Network:
opencodehub-network - Command:
redis-server --appendonly yes --requirepass YOUR_PASS - Shared Folders:
/share/Container/opencodehub/redis → /data
- Search and install
opencodehub/opencodehub:latest - Name:
opencodehub - Network:
opencodehub-network - Environment variables (same as Synology example)
- Shared Folders:
/share/Container/opencodehub/repos → /data/repos /share/Container/opencodehub/storage → /data/storage /share/Container/opencodehub/ssh → /data/ssh /share/Container/opencodehub/cache → /data/cache - Ports:
4321,2222
- Control Panel → System → Reverse Proxy
- Click Create
- Rule:
- Name:
OpenCodeHub - Source Protocol: HTTPS
- Source URL:
git.yourdomain.com - Port: 443
- Destination Protocol: HTTP
- Destination URL:
localhost - Port: 4321
- Name:
- Enable HSTS
- Control Panel → Security → Certificate & Private Key
- Click Replace Certificate
- Choose Get from Let's Encrypt
- Enter your domain and email
- Click Apply
If your NAS supports Docker (via Portainer, Podman, or CLI):
# Create directories
mkdir -p ~/opencodehub/{repos,storage,ssh,cache,postgres,redis}
# Create docker-compose.yml
cat > ~/opencodehub/docker-compose.yml << 'EOF'
version: '3.8'
services:
app:
image: opencodehub/opencodehub:latest
container_name: opencodehub
restart: unless-stopped
ports:
- "4321:4321"
- "2222:2222"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://opencodehub:YOUR_PASS@postgres:5432/opencodehub
- REDIS_URL=redis://:YOUR_PASS@redis:6379
- JWT_SECRET=YOUR_SECRET
- SESSION_SECRET=YOUR_SECRET
- INTERNAL_HOOK_SECRET=YOUR_SECRET
- CRON_SECRET=YOUR_SECRET
- RUNNER_SECRET=YOUR_SECRET
- WORKFLOW_SECRET_ENCRYPTION_KEY=YOUR_SECRET
- SITE_URL=https://git.yourdomain.com
- STORAGE_TYPE=local
- STORAGE_PATH=/data/storage
- REPOS_PATH=/data/repos
- SSH_HOST_KEY_PATH=/data/ssh/host_key
volumes:
- ./repos:/data/repos
- ./storage:/data/storage
- ./ssh:/data/ssh
- ./cache:/data/cache
depends_on:
- postgres
- redis
networks:
- och-net
postgres:
image: postgres:16-alpine
container_name: opencodehub-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=opencodehub
- POSTGRES_PASSWORD=YOUR_PASS
- POSTGRES_DB=opencodehub
volumes:
- ./postgres:/var/lib/postgresql/data
networks:
- och-net
redis:
image: redis:7-alpine
container_name: opencodehub-redis
restart: unless-stopped
command: redis-server --appendonly yes --requirepass YOUR_PASS
volumes:
- ./redis:/data
networks:
- och-net
networks:
och-net:
driver: bridge
EOF
# Deploy
cd ~/opencodehub
docker-compose up -dFor external access, forward these ports on your router:
| External Port | Internal IP | Internal Port | Purpose |
|---|---|---|---|
| 80 | Your NAS IP | 80 | HTTP (for Let's Encrypt/redirect) |
| 443 | Your NAS IP | 443 | HTTPS (OpenCodeHub web) |
| 2222 | Your NAS IP | 2222 | SSH Git (optional) |
Security Note: If using a reverse proxy, you only need to forward 80 and 443. Port 4321 should NOT be exposed externally.
If you don't have a static IP:
- Control Panel → External Access → DDNS
- Click Add
- Service Provider: Synology, No-IP, DuckDNS, etc.
- Enter hostname:
git.yourddns.net - Click Test Connection → OK
- Network → Global Configuration → Nameservers
- Use Cloudflare or your DNS provider's API for dynamic updates
- Or install a DDNS client as a custom app
- Control Panel → Network & File Services → DDNS
- Click Add
- Select provider and configure
Most routers (UniFi, ASUS, TP-Link) have built-in DDNS. Configure it to update git.yourddns.net automatically.
# Synology/QNAP/Generic
ssh admin@your-nas-ip
docker exec -it opencodehub bun run scripts/seed-admin.ts
# TrueNAS
kubectl exec -it deployment/opencodehub -- bun run scripts/seed-admin.tsEnter username, email, and password.
- Visit
https://git.yourddns.net(or your domain) - Log in with admin credentials
- Create your first organization
- Test Git over HTTPS:
git clone https://git.yourddns.net/admin/test-repo.git
cd ~/opencodehub # or /volume1/docker/OpenCodeHub, etc.
docker-compose pull
docker-compose up -d- Hyper Backup → Create → Local/Remote
- Select
opencodehubshared folder - Schedule: Daily at 2 AM
- Retention: Keep last 7 versions
# Backup script
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/path/to/backups"
# Database
docker exec opencodehub-postgres pg_dump -U opencodehub opencodehub | gzip > $BACKUP_DIR/och-db-$DATE.sql.gz
# Files
tar czf $BACKUP_DIR/och-files-$DATE.tar.gz /path/to/opencodehub/repos /path/to/opencodehub/storage
# Keep only last 7 days
find $BACKUP_DIR -name "och-*" -mtime +7 -delete| NAS | Monitoring Tool |
|---|---|
| Synology | Resource Monitor widget |
| TrueNAS | Reporting → CPU/Memory/Disk |
| QNAP | Resource Monitor in Dashboard |
OpenCodeHub on NAS typically uses:
- RAM: 1-2GB idle, 2-4GB under load
- CPU: 10-30% during normal use
- Disk: Grows with repos and uploads
| Problem | Solution |
|---|---|
| Container won't start | Check logs: docker logs opencodehub. Often a database connection issue. |
| "host.docker.internal" not found | Use your NAS's LAN IP (e.g., 192.168.1.100) instead of host.docker.internal. |
| Permission denied on volumes | Ensure the Docker user has read/write access to the shared folders. On Synology, set permissions for the Docker group. |
| Slow performance | NAS devices often have slow CPUs. Ensure you have at least 4GB RAM. Consider using SSD for the postgres volume. |
| SSL certificate errors | Ensure your domain resolves correctly. Check DDNS is updating your IP. |
| Git SSH not connecting | Port 2222 must be forwarded on router. Some ISPs block port 22/2222. Try a different high port (e.g., 8022). |
| Database corruption after power loss | PostgreSQL with default settings can corrupt on unclean shutdown. Use a UPS. For extra safety, add fsync=on to PostgreSQL config. |
| Out of memory | Synology/QNAP with 2GB RAM will struggle. Close unused packages. Add a swap file if needed. |
- Enable Snapshot Replication for instant recovery
- Use SSO Client if you want to integrate with existing domain auth
- Consider Virtual Machine Manager if you need more isolation
- Use Apps instead of VMs for better resource efficiency
- Enable Automatic container updates in TrueNAS settings
- Consider TrueCharts catalog for additional apps
- Use QuTS hero (ZFS) for better data integrity
- Enable ** snapshots** for the opencodehub dataset
- QVPN can secure remote access without exposing ports
- Configure Email (SMTP)
- Set up Offsite Storage (S3/R2) — highly recommended for NAS (protects against drive failure)
- Enable Branch Protection
- Set up your First Stack