This version is implemented in Go with server-rendered HTML and HTMX for form submissions.
go run ./cmd/serverOpen http://127.0.0.1:8080.
Editable in the UI:
- milestone
- repository
- label
- two GitHub logins
- optional GitHub token for the current request only
Optional server defaults:
DEFAULT_TARGET_REPODEFAULT_TARGET_LABELDEFAULT_USER_ADEFAULT_USER_BHOSTPORTGITHUB_TOKENorGH_TOKEN
Copy .env.example to a real env file on the server and fill in GITHUB_TOKEN if you want higher GitHub API limits.
make test
make build
make build-linux
make runThis app is designed to run on a small Ubuntu Linode with:
systemdkeeping the Go binary aliveCaddyreverse proxying to127.0.0.1:8080- a server-side env file at
/etc/issue-report.env
The easiest path is:
- create the Linode
- install packages on the server
- create the env file
- run the deploy script from your local machine
- Use Ubuntu 24.04 LTS or another recent Ubuntu release.
- Add your SSH key during provisioning if possible.
- Make note of the public IP.
From your local machine:
ssh root@YOUR_LINODE_IPRun this on the Linode:
apt update
apt install -y caddy rsyncRun this on the Linode:
useradd --system --home /opt/issue-report --shell /usr/sbin/nologin issue-report || true
mkdir -p /opt/issue-report/bin /opt/issue-report/public /opt/issue-report/deploy
chown -R issue-report:issue-report /opt/issue-reportRun this on the Linode:
cat >/etc/issue-report.env <<'EOF'
HOST=127.0.0.1
PORT=8080
DEFAULT_TARGET_REPO=rancher/rancher
DEFAULT_TARGET_LABEL=team/frameworks
DEFAULT_USER_A=brudnak
DEFAULT_USER_B=fillipehmeireles
GITHUB_TOKEN=your_server_side_token_here
EOF
chmod 600 /etc/issue-report.envNotes:
GITHUB_TOKENis optional for public repos, but recommended to avoid rate limits.HOST=127.0.0.1is correct because Caddy will proxy local traffic to the app.
If you are using ufw, run this on the Linode:
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
ufw statusFrom your project directory on your local machine:
DEPLOY_HOST=YOUR_LINODE_IP DEPLOY_USER=root ./scripts/deploy-linode.shIf you already have a domain pointed at the Linode, use:
DEPLOY_HOST=YOUR_LINODE_IP DEPLOY_DOMAIN=report.example.com DEPLOY_USER=root ./scripts/deploy-linode.shWhat the deploy script does:
- builds the Linux binary locally
- copies the binary plus
public/anddeploy/to/opt/issue-report - installs the
systemdunit at/etc/systemd/system/issue-report.service - generates
/etc/caddy/Caddyfile - enables and restarts the app
- reloads Caddy
Run these on the Linode:
systemctl status issue-report --no-pager
systemctl status caddy --no-pager
curl http://127.0.0.1:8080/healthzIf you deployed by IP:
curl http://YOUR_LINODE_IP/healthzIf you deployed with a domain:
curl https://report.example.com/healthzRun these on the Linode:
journalctl -u issue-report -n 100 --no-pager
journalctl -u caddy -n 100 --no-pager
systemctl restart issue-report
systemctl reload caddy
caddy validate --config /etc/caddy/CaddyfileFrom your local machine, after pulling or editing the repo:
DEPLOY_HOST=YOUR_LINODE_IP DEPLOY_USER=root ./scripts/deploy-linode.shOr with a domain:
DEPLOY_HOST=YOUR_LINODE_IP DEPLOY_DOMAIN=report.example.com DEPLOY_USER=root ./scripts/deploy-linode.shThat is enough for normal updates. You do not need to manually copy files if you use the deploy script.
Both work:
- If you set
DEPLOY_DOMAIN, Caddy serves the app on that hostname and can manage HTTPS normally. - If you omit
DEPLOY_DOMAIN, the script configures Caddy forhttp://YOUR_LINODE_IP, which is fine for internal review or early testing.
For anything long-lived, use a real domain.
After deployment, the server should roughly look like this:
/opt/issue-report/
bin/issue-report
public/
deploy/
/etc/issue-report.env
/etc/systemd/system/issue-report.service
/etc/caddy/Caddyfile
The app exposes:
GET /healthz
It returns 200 OK with ok.
- This app does not need GitHub CLI on the server.
- It talks directly to the GitHub API.
- For a public repo, the app works without a token, but rate limits are lower.
- The deploy helper lives at
scripts/deploy-linode.sh. - The
systemdunit template isdeploy/issue-report.service.
- A token in server-side environment variables is the safe deployment model.
- A token embedded in browser JavaScript or committed into the repo is not safe.
- Because this targets a public repo, no token is strictly required, but GitHub rate limits are lower without one.