- Relative Paths: Use relative paths in the local
docker-compose.ymlfile. The.involumes: - .:/srcmeans “mount the directory where thisdocker-compose.ymlfile lives.” This works universally on Windows, macOS, or Linux machines regardless of the user’s specific local file structure (e.g., C:\Users\Dev\Project vs. /home/dev/Project). - Generic Image: Use a standard, public Hugo image (e.g.,
hugomods/hugo). - Unraid Handles Unraid Logic: Your Unraid server manages its own configurations, which might involve different paths (e.g.,
/mnt/user/data/siteA:/src), specific UIDs/GIDs (PUID/PGID variables), and production-specific commands.
The Developer’s Portable docker-compose.yml (Recommended)
This simple file is committed to your repository so every developer gets the exact same setup:
<em># In the root of the cloned Hugo repo</em>
version: "3.3"
services:
hugo_dev:
image: hugomods/hugo:exts
<em># Use relative path '.' which works everywhere</em>
volumes:
- .:/src
ports:
- "1313:1313"
<em># Ensure non-root user for local file permissions (as discussed before)</em>
user: "${UID}:${GID}"
<em># Standard command to run the server</em>
command: hugo server -D --bind 0.0.0.0
The Unraid Production/Staging Setup
This setup is entirely separate and configured within Unraid’s Docker management system or a different docker-compose.yml file maintained on the Unraid server:
- Paths: Uses Unraid-specific absolute paths like
/mnt/user/data/site1/public:/usr/share/nginx/html. - Images: Might use an
nginximage rather than ahugoserver image. - Variables: Uses specific PUID/PGID matching your Unraid user.
By separating the two environments, you get the flexibility of local development (Option 2) while maintaining the specific requirements of your Unraid host and production architecture.
The CI/CD pipeline does not need to know who made the change, only that a change has occurred in the remote repository. The pipeline is triggered automatically by the event of a developer pushing code to the central Git repository (e.g., GitHub, GitLab).
Here is how the pipeline detects and acts on changes, using the commit message prefixes (feat:, fix:, etc.) for specific actions:
1. The Trigger: A git push Event
The CI/CD pipeline starts when a developer pushes their commits from their local machine to the remote Git repository.
- Webhooks: The Git hosting service (GitHub, etc.) uses a webhook to send a signal to your CI/CD runner (e.g., Jenkins, GitHub Actions, GitLab CI) saying, “Code has been pushed to the main branch.”
- Pipeline Starts: The CI/CD runner picks up this signal and begins executing the predefined steps in your pipeline script (usually a YAML file in the repo).
2. Utilizing Commit Messages for Logic
The commit message prefixes you mentioned are part of the Conventional Commits standard, primarily used for automated versioning and changelog generation.
fix:usually means a patch version bump (e.g., v1.0.1).feat:usually means a minor version bump (e.g., v1.1.0).MAJOR:(or footerBREAKING CHANGE:) means a major version bump (e.g., v2.0.0).
Your CI/CD pipeline script can read and parse these commit messages to decide what to do next:
- Filtering by Branch: The most common approach is to only run a deployment to the Unraid “verification” (staging) environment when code is pushed to a specific branch, such as
developorstaging. - Filtering by Commit Type: You can add logic within your pipeline steps to check the commit message:
- Example Logic: “If the commit message contains
docs:orchore:, just build the site and run basic tests, but don’t deploy to Unraid.” - Deployment Logic: “If the commit message contains
feat:orfix:, proceed with the build, test, and automated deployment to the Unraid staging environment.”
- Example Logic: “If the commit message contains
3. The Deployment to Unraid: “Pull” vs. “Push”
Once triggered, the pipeline needs to get the new code onto the Unraid server. In a secure, containerized setup, the CI/CD runner typically builds a new Docker image containing the Hugo site’s static files and then deploys that new image, rather than simply telling Unraid to “pull” the Git repo.
The CI/CD Process Steps:
- Source: Developer pushes code to Git.
- Trigger: Webhook activates the CI/CD pipeline.
- Build (CI Runner): The runner clones the repo (including submodules), runs
hugo buildinside a container to generate the static files. - Package (Optional but Recommended): The built static files are packaged into a new, lightweight Nginx Docker image. The commit message type (feat, fix) might automate a version tag for this image (e.g.,
myregistry/site1:1.1.0). - Push: The new Nginx image is pushed to a Docker registry (Docker Hub, GitLab Registry, your own Unraid registry).
- Deploy (CD Runner – on Unraid): The final stage remotely commands the Unraid server to pull and run the newly created Docker image, replacing the old container.
Summary of How it Detects Changes
The pipeline detects the act of a developer pushing changes to the central repository via a webhook trigger. It then uses the commit history and message structure (feat:, fix:) to determine the scope of the change and decide whether to initiate a full deployment pipeline for verification on the Unraid server.
PUSH vs. PULL in Deployment
| Feature | Push-Based Deployment | Pull-Based Deployment (GitOps) |
|---|---|---|
| Initiator | External CI/CD Server | Internal Agent/Operator on Unraid |
| Mechanism | CI/CD server uses SSH/API to command the Unraid host | Agent on Unraid continuously monitors Git/Registry |
| Access | CI/CD server needs admin access to Unraid | Unraid only needs access to the Registry/Git |
| Security | Higher risk (external access required) | Lower risk (access confined internally) |
How the “PULL” in Step 6 Works
In your scenario, the pipeline execution on your CI/CD runner (e.g., GitHub Actions, Jenkins) is running outside the Unraid environment. To trigger a pull on the Unraid machine securely, you have a few mechanisms:
Mechanism A: CI/CD initiates the PULL command via SSH (Hybrid Approach)
This is the most common way to deploy to a private server like Unraid without a full “GitOps operator”.
- CI/CD Pipeline (External): Builds the new Nginx image, pushes it to a registry (e.g., Docker Hub).
- SSH Command: The final step in the pipeline uses SSH to securely connect to the Unraid host machine.
- Unraid Command Line: The SSH command executes a script on the Unraid server:
docker pull myregistry/site1:latest(Pulls the new image)docker stop site1_containerdocker rm site1_containerdocker run ... myregistry/site1:latest(Starts the new container)
The action on the Unraid side is a pull, but the trigger for that action is an external system pushing a command via SSH.
Mechanism B: A GitOps Operator on Unraid (Pure PULL)
This is the most secure and modern “GitOps” approach. You install an agent/operator on the Unraid server (like FluxCD or ArgoCD, if you were using Kubernetes/K3s, or a simple tool like Watchtower for basic image updates).
- CI/CD Pipeline (External): Builds the image and pushes it to the registry. The pipeline ends here.
- Unraid Agent (Internal): The agent runs continuously inside your Unraid environment.
- Monitoring: The agent periodically checks the Docker registry for the “latest” tag or a new version tag.
- Automatic Pull/Update: When the agent detects a new image version, it automatically pulls the image and restarts the corresponding container.
Clarification on Step 6
In the context of standard CI/CD pipelines deploying to a private server via SSH (Mechanism A), the overall process is considered push-based deployment because the external CI server has the control and initiates the connection and deployment steps.
The specific command docker pull on the remote machine is just one step in that push-initiated process.
To summarize:
- You, the developer, PUSH code to the Git repo.
- The CI/CD pipeline PUSHES a built Docker image to a registry.
- The CI/CD pipeline PUSHES a command (via SSH) to Unraid, telling Unraid to PULL that new image and restart the service.
Option 2 remains the recommended method for secure, isolated development using standard Git workflows.
