Building a Docker Image for Yohaku with GitHub Actions
Preface
26/4/25 update: The Workflow now adds submodules fetching to avoid missing variables. 26/5/24 update: Following upstream core v13 changes, /api/v2 was changed to /api/v3
Innei went crazy using Claude and other AI tools rewrote Shiroi’s design style and renamed it to Yohaku. But the refactor took such a big step that it introduced a bunch of breaking changes, and the image originally built with GitHub Actions could no longer be used normally after deployment. After using the “help me, Copilot” method to troubleshoot and fix the issue, I整理了一下问题,结合原有的资料,写一版 2026 年用 Actions 构建一个能跑的 Yohaku Docker 镜像的教程。
What changed?
The short version: environment variables that only needed to be added at runtime now also need to be passed during the build, otherwise the compiled artifact will be deployed using the original method and will crash on access with Invalid base URL: /api/v3/auth.
The reason is that BASE_URL and other parameters were not injected when building the image, causing the build step to compile NEXT_PUBLIC_API_URL as /api/v3 by default. When the container starts and performs server-side rendering, it reads the packaged compiled artifact, and NEXT_PUBLIC_API_URL is still hardcoded as /api/v3, so an error occurs. Therefore, BASE_URL needs to be set during the build stage.
Approach
Similar to PaloMiku’s earlier tutorial but with differences: use GitHub Actions to periodically pull updates from the upstream private repository, apply your own changes with a rebase operation, and then use another workflow to add variables, build the Docker image, and publish it to GitHub Packages.
The first half of the workflow can refer to the tutorial I wrote: Troubleshooting | Actions sync upstream projects and merge into your own branch
The Workflow for the image-building part is as follows (using a bunch of wheels). Create a new yml workflow under the .github/workflows directory and paste and commit the following content:
name: Create and publish a Docker image
# Automatically trigger the workflow when the main branch changes
on:
push:
branches: ['main']
# Define the image registry and image name
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Set GITHUB_TOKEN permissions
permissions:
contents: read
packages: write
attestations: write
id-token: write
#
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
submodules: true
# Log in to the image registry
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract tags and labels for the image in the workflow
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
type=sha
# Build the image using the repository's Dockerfile, use the tags and labels defined in the previous step, and push to ghcr.io, where build-args are used to declare variable values before compilation.
- name: Build and push Docker image
id: push
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
S3_ACCESS_KEY=${{ secrets.S3_ACCESS_KEY }}
S3_SECRET_KEY=${{ secrets.S3_SECRET_KEY }}
WEBHOOK_SECRET=${{ secrets.WEBHOOK_SECRET }}
TMDB_API_KEY=${{ secrets.TMDB_API_KEY }}
GH_TOKEN=${{ secrets.GH_TOKEN }}
BASE_URL=${{ secrets.BASE_URL }}
This allows simple building and uploading to the Github Registry image. In addition, at minimum you need to configure the BASE_URL variable in Repository secrets under the repository’s Settings → Secrets and variables → Actions; the value should be the domain bound to the deployed Core backend (for example, https://api.example.com), and other variables can be added as needed. After that, run the workflow once to build the image.
As for why NEXT_PUBLIC_API_URL and NEXT_PUBLIC_GATEWAY_URL are not configured, the main reason is that the repository’s built-in Dockerfile already states that the values of these two variables are based on BASE_URL, so they do not need to be added. Of course, if there are issues, you can also add the corresponding variables in the Workflow and Secret.
Usage
After compilation, you can find the image you built in Packages on the right side of your project page.
Before pulling the image on the server, you need to configure the Docker private registry first. Enter the following command to log in to the Github Registry private registry:
docker login ghcr.io
Enter your account and a Github Access Token with access permissions, and after confirming the login, you can pull images from the private registry. If you are using 1Panel, you can also directly add the private registry configuration under Containers → Registry.
After configuration, you can directly deploy the image using the following Docker Compose file:
services:
shiro:
container_name: shiroi
image:
restart: always
environment:
# Keep the following two lines to ensure compatibility
- NEXT_PUBLIC_API_URL=https://api.example.com/api/v3
- NEXT_PUBLIC_GATEWAY_URL=https://api.example.com
- NEXT_SHARP_PATH=/usr/local/lib/node_modules/sharp
- BASE_URL=https://api.example.com
ports:
- 127.0.0.1:2323:2323
Fill in images with the image information you see (generally, the image will be named directly after the repository, such as ghcr.io/username/repo_name:latest)
Closing
With that, the tutorial for building images with Actions and deploying them directly is basically complete. The key point is still introducing variables during the image build process; the other steps are not much different. If you have questions, you can ask in the comments or use AI and search engines to understand it.
Reference content and related links are as follows:
- PaloMiku’s GitHub Action builds Shiroi Docker image
- innei-dev/shiroi-deploy-action (Innei’s automated deployment wheel for Yohaku; the Readme also says that variables need to be passed during the build)
- Troubleshooting | Actions sync upstream projects and merge into your own branch