Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Finsys/dockhand/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Dockhand’s Git integration enables automatic deployment of Docker Compose stacks directly from Git repositories. Connect to GitHub, GitLab, or any Git server and automatically sync changes, trigger deployments via webhooks, and maintain version-controlled infrastructure.
Key Features
- Repository Management: Connect to any Git repository (GitHub, GitLab, Bitbucket, self-hosted)
- Automatic Sync: Schedule periodic syncs to check for updates
- Webhook Support: Instant deployments triggered by Git push events
- Credential Management: Secure storage for SSH keys and access tokens
- Multi-Stack Support: Deploy multiple stacks from a single repository
- Branch Selection: Deploy from any branch (main, develop, feature branches)
- Environment Files: Automatic
.env file handling from repository
Repository Configuration
Creating a Git Repository Connection
- Navigate to Git → Repositories
- Click Add Repository
- Configure the repository settings:
{
"name": "my-app",
"url": "https://github.com/username/repo.git",
"branch": "main",
"composePath": "compose.yaml",
"credentialId": 1
}
Authentication Methods
Dockhand supports multiple authentication methods:
SSH Key Authentication
// Recommended for private repositories
{
"authType": "ssh",
"sshPrivateKey": "-----BEGIN OPENSSH PRIVATE KEY-----\n...",
"sshPassphrase": "optional-passphrase"
}
HTTPS with Token
{
"authType": "https",
"username": "git",
"password": "ghp_yourGitHubToken"
}
Public Repositories
Git Stacks
What are Git Stacks?
Git stacks are Docker Compose stacks that are automatically deployed from a Git repository. They maintain synchronization with the repository and can be configured for automatic updates.
Creating a Git Stack
{
"stackName": "production-app",
"repositoryId": 1,
"environmentId": 1,
"composePath": "docker-compose.prod.yml",
"envFilePath": ".env.production",
"autoUpdate": true,
"autoUpdateCron": "0 3 * * *"
}
Stack Deployment Process
When a Git stack is deployed, Dockhand:
- Clones or pulls the latest changes from the repository
- Checks out the specified branch
- Loads environment variables from the
.env file (if specified)
- Applies stack variables from Dockhand’s variable management
- Runs docker compose up with the specified compose file
- Records deployment logs for audit and troubleshooting
Webhook Integration
GitHub Webhooks
-
Get your webhook URL from Dockhand:
https://dockhand.example.com/api/git/webhook/{repositoryId}
-
In your GitHub repository, go to Settings → Webhooks → Add webhook
-
Configure the webhook:
- Payload URL: Your Dockhand webhook URL
- Content type:
application/json
- Secret: Generate a secret in Dockhand and paste it here
- Events: Select “Just the push event”
GitLab Webhooks
-
In your GitLab project, go to Settings → Webhooks
-
Configure the webhook:
- URL: Your Dockhand webhook URL
- Secret token: Your Dockhand webhook secret
- Trigger: Check “Push events”
- SSL verification: Enable for production
Webhook Security
Dockhand verifies webhook signatures to ensure authenticity:
function verifySignature(payload: string, signature: string | null, secret: string): boolean {
if (!signature) return false;
// GitHub: sha256=<hash>
if (signature.startsWith('sha256=')) {
const expectedSignature = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// GitLab: direct token comparison
return signature === secret;
}
Automatic Sync
Scheduled Synchronization
Configure automatic sync with cron expressions:
// Check for updates every 6 hours
{
"autoUpdate": true,
"autoUpdateCron": "0 */6 * * *"
}
// Daily at 3 AM
{
"autoUpdate": true,
"autoUpdateCron": "0 3 * * *"
}
// Every 15 minutes
{
"autoUpdate": true,
"autoUpdateCron": "*/15 * * * *"
}
Sync Behavior
The scheduler implements intelligent sync behavior:
export async function runGitStackSync(
stackId: number,
stackName: string,
environmentId: number | null | undefined,
triggeredBy: ScheduleTrigger
): Promise<void> {
const startTime = Date.now();
// Create execution record
const execution = await createScheduleExecution({
scheduleType: 'git_stack_sync',
scheduleId: stackId,
environmentId: environmentId ?? null,
entityName: stackName,
triggeredBy,
status: 'running'
});
// Deploy the git stack (only if there are changes)
const result = await deployGitStack(stackId, { force: false });
if (result.success) {
if (result.skipped) {
log(`No changes detected for stack: ${stackName}, skipping redeploy`);
// Send notification for skipped sync
await sendEventNotification('git_sync_skipped', {
title: 'Git sync skipped',
message: `Stack "${stackName}" sync skipped: no changes detected`,
type: 'info'
}, envId);
} else {
log(`Successfully deployed stack: ${stackName}`);
// Send notification for successful sync
await sendEventNotification('git_sync_success', {
title: 'Git stack deployed',
message: `Stack "${stackName}" was synced and deployed successfully`,
type: 'success'
}, envId);
}
}
}
Environment Variables
Repository .env Files
Dockhand can automatically load environment variables from files in your repository:
# Repository structure
.
├── compose.yaml
├── .env.production
├── .env.staging
└── .env.development
Configure which file to use:
{
"envFilePath": ".env.production"
}
Stack Variable Override
Variables defined in Dockhand take precedence over repository files:
- Repository
.env file (lowest priority)
- Stack-specific variables in Dockhand
- Environment variables set at deploy time (highest priority)
Manual Operations
Sync Repository
Manually trigger a sync to check for updates:
POST /api/git/repositories/{id}/sync
Response:
{
"success": true,
"hasChanges": true,
"currentCommit": "abc123",
"latestCommit": "def456"
}
Deploy Stack
Manually deploy a Git stack:
POST /api/git/stacks/{id}/deploy
The API uses Server-Sent Events (SSE) for real-time deployment progress:
export const POST: RequestHandler = async (event) => {
const { params, cookies } = event;
const auth = await authorize(cookies);
const id = parseInt(params.id);
const gitStack = await getGitStack(id);
if (!gitStack) {
return json({ error: 'Git stack not found' }, { status: 404 });
}
// Permission check with environment context
if (auth.authEnabled && !await auth.can('stacks', 'start', gitStack.environmentId || undefined)) {
return json({ error: 'Permission denied' }, { status: 403 });
}
return createJobResponse(async (send) => {
try {
const result = await deployGitStack(id);
await auditGitStack(event, 'deploy', id, gitStack.stackName, gitStack.environmentId);
send('result', result);
} catch (error) {
console.error('Failed to deploy git stack:', error);
send('result', { success: false, error: 'Failed to deploy git stack' });
}
}, event.request);
};
Best Practices
Repository Structure
# Recommended repository layout
my-app/
├── compose.yaml # Main compose file
├── compose.prod.yaml # Production overrides
├── compose.dev.yaml # Development overrides
├── .env.example # Template for environment variables
├── .env.production # Production variables (gitignored)
├── .env.staging # Staging variables (gitignored)
└── docker/
├── nginx/
│ └── nginx.conf
└── app/
└── Dockerfile
Security Recommendations
- Never commit secrets to your repository
- Use webhook secrets to verify authenticity
- Rotate credentials periodically
- Use read-only deploy keys when possible
- Enable SSL verification for webhooks
- Store sensitive env vars in Dockhand, not in repository files
Deployment Strategies
Blue-Green Deployments
Use Git branches for zero-downtime deployments:
# Create two stacks from different branches
production-blue:
branch: release/blue
production-green:
branch: release/green
Multi-Environment Setup
[
{
"name": "app-production",
"branch": "main",
"environmentId": 1,
"composePath": "compose.prod.yaml"
},
{
"name": "app-staging",
"branch": "develop",
"environmentId": 2,
"composePath": "compose.staging.yaml"
},
{
"name": "app-preview",
"branch": "feature/new-feature",
"environmentId": 3,
"composePath": "compose.yaml"
}
]
Troubleshooting
Common Issues
Authentication Failed
Error: Authentication failed
Solution: Verify credentials and ensure the token has repository access
Webhook Not Triggering
- Check webhook secret matches in both GitHub/GitLab and Dockhand
- Verify webhook URL is accessible from the internet
- Check webhook delivery logs in your Git provider
- Ensure SSL certificate is valid (or disable verification for testing)
Stack Not Updating
Status: "No changes detected"
Solution: Verify the correct branch is configured and commits are pushed
Viewing Sync Logs
All sync operations are logged and can be viewed in the Schedule Executions page:
GET /api/schedules/executions?scheduleType=git_stack_sync
API Reference
Repository Endpoints
# List repositories
GET /api/git/repositories
# Create repository
POST /api/git/repositories
# Update repository
PUT /api/git/repositories/{id}
# Delete repository
DELETE /api/git/repositories/{id}
# Sync repository
POST /api/git/repositories/{id}/sync
# Test repository connection
POST /api/git/repositories/{id}/test
Stack Endpoints
# List Git stacks
GET /api/git/stacks
# Create Git stack
POST /api/git/stacks
# Update Git stack
PUT /api/git/stacks/{id}
# Delete Git stack
DELETE /api/git/stacks/{id}
# Deploy Git stack
POST /api/git/stacks/{id}/deploy
# Sync Git stack
POST /api/git/stacks/{id}/sync
# Get webhook URL
GET /api/git/stacks/{id}/webhook
Credential Endpoints
# List credentials
GET /api/git/credentials
# Create credential
POST /api/git/credentials
# Update credential
PUT /api/git/credentials/{id}
# Delete credential
DELETE /api/git/credentials/{id}