This guide describes how to configure the Huly GitHub integration for a self-hosted deployment.
It covers the full path from GitHub App registration to Huly compose.yml, reverse proxy wiring, verification, and troubleshooting.
There are two different GitHub-related features in Huly:
- GitHub OAuth login
- GitHub service integration for repository, issue, pull request, comment, and review sync
They are not the same thing.
GitHub OAuth login is used for signing users into Huly and relies on:
GITHUB_CLIENT_IDGITHUB_CLIENT_SECRET
The GitHub service integration uses a GitHub App and relies on:
GITHUB_APPIDGITHUB_APP_SLUGGITHUB_CLIENTIDGITHUB_CLIENT_SECRETGITHUB_PRIVATE_KEYGITHUB_WEBHOOK_SECRET
Important:
GITHUB_CLIENT_ID and GITHUB_CLIENTID are different variables for different features.
Also note that the secret name GITHUB_CLIENT_SECRET is reused in documentation and deployments for both contexts.
That only stays unambiguous if both flows are backed by the same GitHub App or the same client credentials.
If you use separate GitHub applications for:
- OAuth login
- GitHub repository integration
then a single shared top-level env naming scheme becomes ambiguous. In that case you should keep the credentials separated in your deployment layer and map them explicitly to the process that needs them.
This guide focuses on the GitHub App integration flow.
Before starting, make sure:
- your Huly instance is reachable via HTTPS
- the frontend is reachable from the browser at
https://<your-host>/ - the account service is reachable behind the same host
- your reverse proxy can expose
/_github - you can restart the affected Docker services
For the current huly-dev deployment discussed in this repo, the relevant files are:
/home/alexander/huly-dev/huly_v7.conf/home/alexander/huly-dev/compose.yml/home/alexander/huly-dev/.huly.nginx
Go to GitHub:
SettingsDeveloper settingsGitHub AppsNew GitHub App
Use the following values:
- App name: choose a unique public name such as
my-huly-dev - Homepage URL:
https://<your-host>/ - Callback URL:
https://<your-host>/github - Setup URL:
https://<your-host>/github?op=installation - Redirect on update: enabled
- Webhook URL:
https://<your-host>/_github/api/webhook - Webhook secret: generate a random secret and keep it for
GITHUB_WEBHOOK_SECRET
Set these permissions on the GitHub App:
- Commit statuses:
Read and write - Contents:
Read and write - Custom properties:
Read and write - Discussions:
Read and write - Issues:
Read and write - Metadata:
Read-only - Pages:
Read and write - Projects:
Read and write - Pull requests:
Read and write - Webhooks:
Read and write
Subscribe to these events:
- Issues
- Pull request
- Pull request review
- Pull request review comment
- Pull request review thread
After creating the app, collect these values:
GITHUB_APPIDGITHUB_APP_SLUGGITHUB_CLIENTIDGITHUB_CLIENT_SECRETGITHUB_PRIVATE_KEYGITHUB_WEBHOOK_SECRET
Notes:
GITHUB_APPIDis the numeric app ID from the GitHub App page.GITHUB_APP_SLUGis the slug fromhttps://github.com/apps/<slug>.GITHUB_CLIENTIDis the GitHub App client ID.GITHUB_PRIVATE_KEYmust contain the full PEM content includingBEGINandENDlines.
Store the secrets in your deployment configuration.
For the current self-hosted layout this is typically huly_v7.conf or another environment file loaded by compose.yml.
Add:
GITHUB_APPID=<numeric-app-id>
GITHUB_APP_SLUG=<github-app-slug>
GITHUB_CLIENTID=<github-app-client-id>
GITHUB_CLIENT_SECRET=<github-app-client-secret>
GITHUB_PRIVATE_KEY=<full-private-key>
GITHUB_WEBHOOK_SECRET=<random-webhook-secret>Important:
- do not truncate the private key
- do not accidentally use the OAuth login variable name
GITHUB_CLIENT_IDwhere the GitHub App client IDGITHUB_CLIENTIDis required GITHUB_CLIENT_SECRETis only safe as a single deployment variable if it really belongs to the same GitHub App and flow you are configuring here- after editing the env file, always validate with
docker compose config
If your secret handling does not support multiline values cleanly, store the private key using a mechanism your Compose setup actually supports and verify that the container receives the exact PEM content.
Add this service to your deployment:
github:
image: hardcoreeng/github:${HULY_VERSION}
ports:
- 3500:3500
environment:
- PORT=3500
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- SERVER_SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- STATS_URL=http://stats:4900
- APP_ID=${GITHUB_APPID}
- CLIENT_ID=${GITHUB_CLIENTID}
- CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
- PRIVATE_KEY=${GITHUB_PRIVATE_KEY}
- COLLABORATOR_URL=ws${SECURE:+s}://${HOST_ADDRESS}/_collaborator
- WEBHOOK_SECRET=${GITHUB_WEBHOOK_SECRET}
- FRONT_URL=http${SECURE:+s}://${HOST_ADDRESS}
- BOT_NAME=${GITHUB_APP_SLUG}[bot]
restart: unless-stopped
networks:
- huly_netIn the front service inside compose.yml, add:
- GITHUB_URL=http${SECURE:+s}://${HOST_ADDRESS}/_github
- GITHUB_APP=${GITHUB_APP_SLUG}
- GITHUB_CLIENTID=${GITHUB_CLIENTID}These values are required so the frontend can:
- build the GitHub authorize URL
- build the GitHub app installation URL
- talk to the GitHub integration backend through
/_github
If these values are missing, config.json will expose empty GitHub fields and the UI may redirect to GitHub with client_id=.
In .huly.nginx, uncomment or add the GitHub route:
location /_github {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
rewrite ^/_github(/.*)$ $1 break;
proxy_pass http://github:3500/;
}Without this route:
- the frontend cannot reach the GitHub backend
- webhook delivery will fail
- installation and authorization callbacks may break
After changing the env file, compose.yml, or .huly.nginx, restart the affected containers:
docker compose up -d --no-deps github front nginxIf nginx still points to an old container IP after a recreate, restart it explicitly:
docker compose restart nginxFor the current huly-dev deployment, this mattered after recreating front.
Run:
docker compose configVerify:
- the
githubservice is present frontcontainsGITHUB_URLfrontcontainsGITHUB_APPfrontcontainsGITHUB_CLIENTID
Open:
https://<your-host>/config.json
Verify these are no longer empty:
GITHUB_APPGITHUB_CLIENTIDGITHUB_URL
The route should at least be reachable through the reverse proxy. Even if a specific endpoint returns a non-200 application response, it must not fail because the route is missing.
In Huly:
- Open
Settings - Open
Integrations - Open
GitHub - Click
Connect
Expected behavior:
- authorization redirects to GitHub with a non-empty
client_id - installation redirects to the GitHub App page
- callbacks return to Huly instead of landing on
404
After the configuration is live:
- Authorize the GitHub user account
- Install the GitHub App into a test organization or repository scope
- Select at least one repository
- Connect the repository to an existing Huly project
- Create a test issue in GitHub
- Verify it appears in Huly
- Add a comment in Huly
- Verify the comment syncs back to GitHub
If webhooks are working, sync should happen without manual polling steps.
Typical causes:
frontis missingGITHUB_CLIENTIDconfig.jsonstill exposes empty GitHub fields- an old frontend build is still being served
What to check:
docker compose config- public
config.json - browser cache
- whether
frontwas recreated after env changes
Typical causes:
- Callback URL in the GitHub App does not match
https://<your-host>/github - Setup URL is missing or wrong
- the Huly route handling is old or not deployed
What to check:
- GitHub App
Callback URL - GitHub App
Setup URL - deployed frontend version
Typical causes:
/_githubis not routed in.huly.nginxGITHUB_WEBHOOK_SECRETdoes not match the GitHub App webhook secret- the
githubcontainer is not running
What to check:
docker compose psdocker compose logs github- GitHub App webhook delivery history
Typical causes:
- a stale frontend build
- a stale reverse proxy
- an outdated frontend callback handler
For the fixes currently prepared in this fork, make sure the deployment includes:
a4de9e36eFix login auth and routing regressionsb03e564ddFix GitHub integration connect callback flow760083d22Add GitHub config fallback for authorize flowbcf914cd2Fix login tabs build for deploy
If you want both features, you may need both configurations:
- GitHub OAuth login for user sign-in
- GitHub App service integration for repository synchronization
Do not assume that configuring one automatically configures the other.
The important limitation is that Huly distinguishes the client IDs more clearly than the deployment variable naming does:
- OAuth login expects
GITHUB_CLIENT_ID - GitHub App integration expects
GITHUB_CLIENTID - both setups are often documented with a
GITHUB_CLIENT_SECRET
So if you use different GitHub apps for those two flows, you should not treat one shared GITHUB_CLIENT_SECRET name as magically universal.
Instead, keep the two credential sets distinct in your secret store or deployment templates and only map the correct pair into each runtime.
In particular:
/_accounts/auth/github/callbackbelongs to OAuth login/_github/api/webhookbelongs to the GitHub integration backendhttps://<your-host>/githubis used by the GitHub App callback/setup flow in the frontend
Use this checklist before declaring the setup complete:
- GitHub App exists
- permissions are set correctly
- events are subscribed correctly
- all six integration secrets are present in the deployment
githubservice exists incompose.ymlfronthasGITHUB_URL,GITHUB_APP, andGITHUB_CLIENTID.huly.nginxexposes/_githubdocker compose configshows expanded values- public
config.jsonexposes non-empty GitHub values docker compose psshowsgithub,front, andnginxhealthy/running- Huly can authorize GitHub
- Huly can install the GitHub App
- repository linking works
- webhook-driven sync works in both directions