Merge pull request #358 from outis1one/claude/gitea-standalone-setup-oxoi2e
Claude/gitea standalone setup oxoi2e
This commit is contained in:
@@ -369,7 +369,26 @@ collision.)
|
|||||||
**Has built-in auth — no Authelia needed:**
|
**Has built-in auth — no Authelia needed:**
|
||||||
`emby`, `jellyfin`, `audiobookshelf`, `immich`, `mealie`, `actualbudget`,
|
`emby`, `jellyfin`, `audiobookshelf`, `immich`, `mealie`, `actualbudget`,
|
||||||
`homeassistant`, `portainer`, `meshcentral`, `traccar`, `uptimekuma`,
|
`homeassistant`, `portainer`, `meshcentral`, `traccar`, `uptimekuma`,
|
||||||
`filebrowser`, `wg-easy`, `ntfy` (configurable)
|
`filebrowser`, `wg-easy`, `ntfy` (configurable), `gitea`
|
||||||
|
|
||||||
|
**Native OIDC login as an addition, not a Caddy gate — `gitea`'s pattern.**
|
||||||
|
Some apps with their own built-in login *also* have their own "add an
|
||||||
|
OAuth2/OIDC provider" setting — a genuinely different integration from
|
||||||
|
both the forward_auth gate above and the "Enable OpenID" client-registration
|
||||||
|
flow below. `services/gitea.sh`'s `_gitea_offer_authelia_sso()` is the
|
||||||
|
reference: if Authelia is installed, offers to register Gitea as an OIDC
|
||||||
|
client (via `services/authelia.sh`'s `_authelia_provision_oidc_client()` —
|
||||||
|
the same non-interactive, out-param-returning core that
|
||||||
|
`_authelia_add_oidc_client()`'s menu flow uses) and then runs `gitea admin
|
||||||
|
auth add-oauth` itself to add Authelia as an authentication source — no
|
||||||
|
manual web-UI copy-paste on either side, matching this repo's "no manual
|
||||||
|
wizard" philosophy elsewhere in gitea.sh (admin account/token creation).
|
||||||
|
Local login keeps working unchanged; this only adds an extra button on the
|
||||||
|
existing login page. Reuse `_authelia_provision_oidc_client()` (guarded by
|
||||||
|
`declare -F`, same convention as chaining into another service's
|
||||||
|
`install_<name>()`) for any future service with its own native OIDC field,
|
||||||
|
instead of duplicating Authelia's client-secret-generation/config-patching
|
||||||
|
logic again.
|
||||||
|
|
||||||
**No built-in auth — should be protected:**
|
**No built-in auth — should be protected:**
|
||||||
`magicmirror`, `wolf-pair`, `js99er`, `drum-rhythm-game`, `iopaint`,
|
`magicmirror`, `wolf-pair`, `js99er`, `drum-rhythm-game`, `iopaint`,
|
||||||
|
|||||||
+120
-57
@@ -1190,12 +1190,32 @@ _authelia_ensure_oidc_provider() {
|
|||||||
log_success "OIDC provider enabled (signing key + HMAC secret generated)"
|
log_success "OIDC provider enabled (signing key + HMAC secret generated)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Registers an OIDC client for another app to log in via Authelia — the
|
# Non-interactive core of _authelia_add_oidc_client() below — generates a
|
||||||
# "Other" provider option in an app's own "Enable OpenID"/SSO dialog. Presets
|
# client secret, patches it into identity_providers.oidc.clients, and
|
||||||
# below hand back the app's own known redirect URI path and the exact fields
|
# (optionally) restarts Authelia. Fully self-contained (re-validates
|
||||||
# to paste where; "Other/custom" covers anything not listed (the app's own
|
# everything itself rather than trusting a caller's state) so other
|
||||||
# OIDC/SSO docs will say what redirect URI it expects).
|
# services can call it directly to register themselves as an OIDC client
|
||||||
_authelia_add_oidc_client() {
|
# without walking a human through this file's own menu — see
|
||||||
|
# services/gitea.sh's "Sign in with Authelia" step for the reference caller.
|
||||||
|
# Guard every cross-file call with `declare -F` per this repo's chaining
|
||||||
|
# convention (services/gitea.sh does).
|
||||||
|
#
|
||||||
|
# Args: APP_NAME CLIENT_ID AUTH_POLICY RESTART_AUTH(y/n) <redirect_uri> [<redirect_uri> ...]
|
||||||
|
# Out-params (not `local` — read them after the call returns):
|
||||||
|
# OIDC_CLIENT_SECRET_PLAIN the plaintext secret. Shown once — Authelia's
|
||||||
|
# config only ever stores the hash — so the
|
||||||
|
# caller must capture and use/display it now.
|
||||||
|
# OIDC_AUTHELIA_DOMAIN this Authelia instance's apex domain, for
|
||||||
|
# building discovery/authorization/token URLs.
|
||||||
|
# Returns 1 on failure (Authelia not installed, client ID already taken,
|
||||||
|
# secret generation failed) with the reason already logged.
|
||||||
|
_authelia_provision_oidc_client() {
|
||||||
|
local APP_NAME="$1" CLIENT_ID="$2" AUTH_POLICY="$3" RESTART_AUTH="$4"; shift 4
|
||||||
|
local -a REDIRECT_URIS=("$@")
|
||||||
|
|
||||||
|
OIDC_CLIENT_SECRET_PLAIN=""
|
||||||
|
OIDC_AUTHELIA_DOMAIN=""
|
||||||
|
|
||||||
local AUTHELIA_DIR="$DOCKER_DIR/authelia"
|
local AUTHELIA_DIR="$DOCKER_DIR/authelia"
|
||||||
local CONFIG_FILE="$AUTHELIA_DIR/config/configuration.yml"
|
local CONFIG_FILE="$AUTHELIA_DIR/config/configuration.yml"
|
||||||
|
|
||||||
@@ -1206,12 +1226,101 @@ _authelia_add_oidc_client() {
|
|||||||
|
|
||||||
_authelia_ensure_oidc_provider "$AUTHELIA_DIR" || return 1
|
_authelia_ensure_oidc_provider "$AUTHELIA_DIR" || return 1
|
||||||
|
|
||||||
|
# The apex domain this Authelia instance already serves — read back from
|
||||||
|
# its own session.cookies (same structure install_authelia()/
|
||||||
|
# add_authelia_domain() write), rather than asking again or assuming a
|
||||||
|
# variable set earlier in this run is still in scope (this flow can be
|
||||||
|
# reached standalone from the "already exists" menu, or from another
|
||||||
|
# service entirely, with none of install_authelia()'s own locals ever
|
||||||
|
# having run this session).
|
||||||
|
OIDC_AUTHELIA_DOMAIN="$(awk '/^ cookies:$/{f=1; next} f && /domain:/{print $3; exit}' "$CONFIG_FILE")"
|
||||||
|
if [ -z "$OIDC_AUTHELIA_DOMAIN" ]; then
|
||||||
|
log_warning "Couldn't determine this Authelia instance's domain from $CONFIG_FILE — aborting."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -qF "client_id: '${CLIENT_ID}'" "$CONFIG_FILE" 2>/dev/null; then
|
||||||
|
log_warning "A client with ID '$CLIENT_ID' is already registered in $CONFIG_FILE."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Generating client secret..."
|
||||||
|
local _hash_out CLIENT_SECRET_HASH
|
||||||
|
_hash_out="$(docker run --rm authelia/authelia:4.39.20 \
|
||||||
|
authelia crypto hash generate pbkdf2 --variant sha512 --random \
|
||||||
|
--random.length 72 --random.charset rfc3986 2>/dev/null)"
|
||||||
|
OIDC_CLIENT_SECRET_PLAIN="$(echo "$_hash_out" | sed -n 's/^Random Password: //p')"
|
||||||
|
CLIENT_SECRET_HASH="$(echo "$_hash_out" | sed -n 's/^Digest: //p')"
|
||||||
|
if [ -z "$OIDC_CLIENT_SECRET_PLAIN" ] || [ -z "$CLIENT_SECRET_HASH" ]; then
|
||||||
|
log_warning "Couldn't generate the client secret automatically. Run manually, then add the"
|
||||||
|
log_warning "client to $CONFIG_FILE's identity_providers.oidc.clients by hand:"
|
||||||
|
echo " docker run --rm authelia/authelia:4.39.20 authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986"
|
||||||
|
OIDC_CLIENT_SECRET_PLAIN=""
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep -q '^ clients: \[\]$' "$CONFIG_FILE" && sed -i 's/^ clients: \[\]$/ clients:/' "$CONFIG_FILE"
|
||||||
|
|
||||||
|
local REDIRECT_URIS_YAML
|
||||||
|
REDIRECT_URIS_YAML="$(printf " - '%s'\n" "${REDIRECT_URIS[@]}")"
|
||||||
|
REDIRECT_URIS_YAML="${REDIRECT_URIS_YAML%$'\n'}"
|
||||||
|
|
||||||
|
local CLIENT_BLOCK=" - client_id: '${CLIENT_ID}'
|
||||||
|
client_name: '${APP_NAME}'
|
||||||
|
client_secret: '${CLIENT_SECRET_HASH}'
|
||||||
|
public: false
|
||||||
|
authorization_policy: '${AUTH_POLICY}'
|
||||||
|
redirect_uris:
|
||||||
|
${REDIRECT_URIS_YAML}
|
||||||
|
scopes:
|
||||||
|
- 'openid'
|
||||||
|
- 'profile'
|
||||||
|
- 'email'
|
||||||
|
grant_types:
|
||||||
|
- 'authorization_code'
|
||||||
|
response_types:
|
||||||
|
- 'code'
|
||||||
|
response_modes:
|
||||||
|
- 'query'
|
||||||
|
userinfo_signed_response_alg: 'none'"
|
||||||
|
|
||||||
|
awk -v block="$CLIENT_BLOCK" '
|
||||||
|
{ print }
|
||||||
|
/^ clients:$/ && !done { print block; done=1 }
|
||||||
|
' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
|
||||||
|
chown 1000:1000 "$CONFIG_FILE" 2>/dev/null || true
|
||||||
|
|
||||||
|
if [[ "$RESTART_AUTH" =~ ^[Yy]$ ]]; then
|
||||||
|
(cd "$AUTHELIA_DIR" && docker compose restart authelia 2>/dev/null) \
|
||||||
|
&& log_success "Authelia restarted" \
|
||||||
|
|| log_warning "Authelia restart failed — check: docker compose logs authelia"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Registers an OIDC client for another app to log in via Authelia — the
|
||||||
|
# "Other" provider option in an app's own "Enable OpenID"/SSO dialog. Presets
|
||||||
|
# below hand back the app's own known redirect URI path and the exact fields
|
||||||
|
# to paste where; "Other/custom" covers anything not listed (the app's own
|
||||||
|
# OIDC/SSO docs will say what redirect URI it expects). Interactive wrapper
|
||||||
|
# around _authelia_provision_oidc_client() above, which does the actual work.
|
||||||
|
_authelia_add_oidc_client() {
|
||||||
|
local AUTHELIA_DIR="$DOCKER_DIR/authelia"
|
||||||
|
local CONFIG_FILE="$AUTHELIA_DIR/config/configuration.yml"
|
||||||
|
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
log_warning "No configuration.yml found at $CONFIG_FILE — install Authelia first."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
# The apex domain this Authelia instance already serves — read back from
|
# The apex domain this Authelia instance already serves — read back from
|
||||||
# its own session.cookies (same structure install_authelia()/
|
# its own session.cookies (same structure install_authelia()/
|
||||||
# add_authelia_domain() write), rather than asking again or assuming a
|
# add_authelia_domain() write), rather than asking again or assuming a
|
||||||
# variable set earlier in this run is still in scope (this flow can be
|
# variable set earlier in this run is still in scope (this flow can be
|
||||||
# reached standalone from the "already exists" menu with none of
|
# reached standalone from the "already exists" menu with none of
|
||||||
# install_authelia()'s own locals ever having run this session).
|
# install_authelia()'s own locals ever having run this session). Used
|
||||||
|
# below only to suggest a domain default — _authelia_provision_oidc_client
|
||||||
|
# re-derives its own copy independently.
|
||||||
local AUTHELIA_DOMAIN
|
local AUTHELIA_DOMAIN
|
||||||
AUTHELIA_DOMAIN="$(awk '/^ cookies:$/{f=1; next} f && /domain:/{print $3; exit}' "$CONFIG_FILE")"
|
AUTHELIA_DOMAIN="$(awk '/^ cookies:$/{f=1; next} f && /domain:/{print $3; exit}' "$CONFIG_FILE")"
|
||||||
if [ -z "$AUTHELIA_DOMAIN" ]; then
|
if [ -z "$AUTHELIA_DOMAIN" ]; then
|
||||||
@@ -1288,58 +1397,12 @@ _authelia_add_oidc_client() {
|
|||||||
prompt_yn " Require two-factor for ${APP_NAME} logins too? (y/n):" "y" _2fa
|
prompt_yn " Require two-factor for ${APP_NAME} logins too? (y/n):" "y" _2fa
|
||||||
[[ "$_2fa" =~ ^[Yy]$ ]] || AUTH_POLICY="one_factor"
|
[[ "$_2fa" =~ ^[Yy]$ ]] || AUTH_POLICY="one_factor"
|
||||||
|
|
||||||
log_info "Generating client secret..."
|
|
||||||
local _hash_out CLIENT_SECRET_PLAIN CLIENT_SECRET_HASH
|
|
||||||
_hash_out="$(docker run --rm authelia/authelia:4.39.20 \
|
|
||||||
authelia crypto hash generate pbkdf2 --variant sha512 --random \
|
|
||||||
--random.length 72 --random.charset rfc3986 2>/dev/null)"
|
|
||||||
CLIENT_SECRET_PLAIN="$(echo "$_hash_out" | sed -n 's/^Random Password: //p')"
|
|
||||||
CLIENT_SECRET_HASH="$(echo "$_hash_out" | sed -n 's/^Digest: //p')"
|
|
||||||
if [ -z "$CLIENT_SECRET_PLAIN" ] || [ -z "$CLIENT_SECRET_HASH" ]; then
|
|
||||||
log_warning "Couldn't generate the client secret automatically. Run manually, then add the"
|
|
||||||
log_warning "client to $CONFIG_FILE's identity_providers.oidc.clients by hand:"
|
|
||||||
echo " docker run --rm authelia/authelia:4.39.20 authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
grep -q '^ clients: \[\]$' "$CONFIG_FILE" && sed -i 's/^ clients: \[\]$/ clients:/' "$CONFIG_FILE"
|
|
||||||
|
|
||||||
local REDIRECT_URIS_YAML
|
|
||||||
REDIRECT_URIS_YAML="$(printf " - '%s'\n" "${REDIRECT_URIS[@]}")"
|
|
||||||
REDIRECT_URIS_YAML="${REDIRECT_URIS_YAML%$'\n'}"
|
|
||||||
|
|
||||||
local CLIENT_BLOCK=" - client_id: '${CLIENT_ID}'
|
|
||||||
client_name: '${APP_NAME}'
|
|
||||||
client_secret: '${CLIENT_SECRET_HASH}'
|
|
||||||
public: false
|
|
||||||
authorization_policy: '${AUTH_POLICY}'
|
|
||||||
redirect_uris:
|
|
||||||
${REDIRECT_URIS_YAML}
|
|
||||||
scopes:
|
|
||||||
- 'openid'
|
|
||||||
- 'profile'
|
|
||||||
- 'email'
|
|
||||||
grant_types:
|
|
||||||
- 'authorization_code'
|
|
||||||
response_types:
|
|
||||||
- 'code'
|
|
||||||
response_modes:
|
|
||||||
- 'query'
|
|
||||||
userinfo_signed_response_alg: 'none'"
|
|
||||||
|
|
||||||
awk -v block="$CLIENT_BLOCK" '
|
|
||||||
{ print }
|
|
||||||
/^ clients:$/ && !done { print block; done=1 }
|
|
||||||
' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
|
|
||||||
chown 1000:1000 "$CONFIG_FILE" 2>/dev/null || true
|
|
||||||
|
|
||||||
local RESTART_AUTH=""
|
local RESTART_AUTH=""
|
||||||
prompt_yn " Restart Authelia to apply? (y/n):" "y" RESTART_AUTH
|
prompt_yn " Restart Authelia to apply? (y/n):" "y" RESTART_AUTH
|
||||||
if [ "$RESTART_AUTH" = "y" ] || [ "$RESTART_AUTH" = "Y" ]; then
|
|
||||||
(cd "$AUTHELIA_DIR" && docker compose restart authelia 2>/dev/null) \
|
_authelia_provision_oidc_client "$APP_NAME" "$CLIENT_ID" "$AUTH_POLICY" "$RESTART_AUTH" "${REDIRECT_URIS[@]}" \
|
||||||
&& log_success "Authelia restarted" \
|
|| return 1
|
||||||
|| log_warning "Restart failed — check: docker compose logs authelia"
|
local CLIENT_SECRET_PLAIN="$OIDC_CLIENT_SECRET_PLAIN"
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " ${APP_NAME} is registered. Paste these into its OpenID/SSO settings"
|
echo " ${APP_NAME} is registered. Paste these into its OpenID/SSO settings"
|
||||||
|
|||||||
+166
-3
@@ -159,7 +159,8 @@ _gitea_prompt_token() {
|
|||||||
# SQLite DB then fails with "attempt to write a readonly database" — the
|
# SQLite DB then fails with "attempt to write a readonly database" — the
|
||||||
# directory holding the DB file is owned by root, not the UID 1000 process
|
# directory holding the DB file is owned by root, not the UID 1000 process
|
||||||
# trying to write it. Confirmed live. Chown everything else as normal in
|
# trying to write it. Confirmed live. Chown everything else as normal in
|
||||||
# $DIR; leave data/ for the container to manage.
|
# $DIR; leave data/ (and the Actions runner's own runner-data/, same reason)
|
||||||
|
# for their respective containers to manage.
|
||||||
_gitea_fix_ownership() {
|
_gitea_fix_ownership() {
|
||||||
local _dir="$1"
|
local _dir="$1"
|
||||||
[ "$DRY_RUN" = true ] && return 0
|
[ "$DRY_RUN" = true ] && return 0
|
||||||
@@ -167,11 +168,141 @@ _gitea_fix_ownership() {
|
|||||||
local _entry
|
local _entry
|
||||||
for _entry in "$_dir"/*; do
|
for _entry in "$_dir"/*; do
|
||||||
[ -e "$_entry" ] || continue
|
[ -e "$_entry" ] || continue
|
||||||
[ "$(basename "$_entry")" = "data" ] && continue
|
case "$(basename "$_entry")" in
|
||||||
|
data|runner-data) continue ;;
|
||||||
|
esac
|
||||||
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$_entry" 2>/dev/null || true
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$_entry" 2>/dev/null || true
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Offers to add "Sign in with Authelia" (OpenID Connect) to Gitea's own
|
||||||
|
# login page. This is a different thing from Caddy forward_auth, which this
|
||||||
|
# service deliberately skips (see the Caddy call below) since Gitea already
|
||||||
|
# has a solid built-in login — this adds Authelia as an *additional* OAuth2
|
||||||
|
# login option on the same page, on top of that built-in login, not a
|
||||||
|
# replacement for it. Nothing about local admin login changes.
|
||||||
|
#
|
||||||
|
# Fully automated on both sides, matching how the rest of this installer
|
||||||
|
# avoids manual web wizards: registers Gitea as an OIDC client in Authelia
|
||||||
|
# (services/authelia.sh's _authelia_provision_oidc_client), then adds the
|
||||||
|
# resulting client as an authentication source in Gitea via its own CLI. If
|
||||||
|
# either side isn't available (Authelia not installed, or the Gitea CLI
|
||||||
|
# call fails for some reason — e.g. an older image without `admin auth
|
||||||
|
# add-oauth`), falls back to printing the values for a two-minute manual
|
||||||
|
# add in Gitea's Site Administration UI instead of losing the setup.
|
||||||
|
_gitea_offer_authelia_sso() {
|
||||||
|
local DIR="$1"
|
||||||
|
|
||||||
|
[ -d "$DOCKER_DIR/authelia" ] || return 0
|
||||||
|
declare -F _authelia_provision_oidc_client >/dev/null 2>&1 || return 0
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
local USE_SSO=""
|
||||||
|
prompt_yn " Add \"Sign in with Authelia\" (OpenID Connect) to Gitea's login page? (y/n):" "n" USE_SSO
|
||||||
|
[[ "$USE_SSO" =~ ^[Yy]$ ]] || return 0
|
||||||
|
|
||||||
|
local _default_domain=""
|
||||||
|
[ -n "${SITE_DOMAIN:-}" ] && [ "$SITE_DOMAIN" != "example.com" ] && _default_domain="git.${SITE_DOMAIN}"
|
||||||
|
local GITEA_OIDC_DOMAIN=""
|
||||||
|
prompt_text " Domain Gitea is reachable at [${_default_domain:-required}]:" "$_default_domain" GITEA_OIDC_DOMAIN
|
||||||
|
if [ -z "$GITEA_OIDC_DOMAIN" ]; then
|
||||||
|
log_warning "No domain entered — skipping Authelia SSO for Gitea."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local _2fa="" AUTH_POLICY="two_factor"
|
||||||
|
prompt_yn " Require two-factor for Gitea logins via Authelia too? (y/n):" "y" _2fa
|
||||||
|
[[ "$_2fa" =~ ^[Yy]$ ]] || AUTH_POLICY="one_factor"
|
||||||
|
|
||||||
|
if ! _authelia_provision_oidc_client "Gitea" "gitea" "$AUTH_POLICY" "y" \
|
||||||
|
"https://${GITEA_OIDC_DOMAIN}/user/oauth2/authelia/callback"; then
|
||||||
|
log_warning "Couldn't register Gitea as an OIDC client in Authelia — skipping SSO setup."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local _discovery_url="https://auth.${OIDC_AUTHELIA_DOMAIN}/.well-known/openid-configuration"
|
||||||
|
log_info "Adding Authelia as an authentication source in Gitea..."
|
||||||
|
if docker exec -u git gitea gitea admin auth add-oauth \
|
||||||
|
--name authelia --provider openidConnect \
|
||||||
|
--key gitea --secret "$OIDC_CLIENT_SECRET_PLAIN" \
|
||||||
|
--auto-discover-url "$_discovery_url" &>/dev/null; then
|
||||||
|
log_success "\"Sign in with Authelia\" added to Gitea's login page — local admin login still works too."
|
||||||
|
else
|
||||||
|
log_warning "Couldn't add the auth source automatically. Add it by hand:"
|
||||||
|
log_warning " Gitea -> Site Administration -> Authentication Sources -> Add Authentication Source"
|
||||||
|
log_warning " Type: OAuth2, Provider: OpenID Connect, Name: authelia"
|
||||||
|
log_warning " Client ID: gitea"
|
||||||
|
log_warning " Client Secret: $OIDC_CLIENT_SECRET_PLAIN"
|
||||||
|
log_warning " Discovery URL: $_discovery_url"
|
||||||
|
log_warning " (The Client Secret above is shown once — it isn't stored in plaintext anywhere.)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Offers to enable Gitea Actions (Gitea's own CI, largely GitHub-Actions-
|
||||||
|
# workflow-compatible) with a local runner — mainly useful as a fallback so
|
||||||
|
# .gitea/workflows/*.yml can still run something like a GitHub Actions build
|
||||||
|
# if GitHub itself is ever unreachable, since this Gitea is otherwise just a
|
||||||
|
# passive pull mirror. Off by default; opt-in on fresh installs and Update
|
||||||
|
# reruns alike (idempotent — a rerun after it's already set up just no-ops).
|
||||||
|
#
|
||||||
|
# The runner (gitea/act_runner) polls Gitea for jobs and needs the host's
|
||||||
|
# Docker socket to launch a fresh container per job — same pattern this repo
|
||||||
|
# already uses for portainer/watchtower/uptimekuma/beszel/traccar's autoheal,
|
||||||
|
# not something new to this file. Worth knowing: that's root-equivalent
|
||||||
|
# access to this host, standard for any CI runner, not unique to Gitea's.
|
||||||
|
_gitea_offer_actions_runner() {
|
||||||
|
local DIR="$1"
|
||||||
|
|
||||||
|
grep -q '^ act_runner:$' "$DIR/docker-compose.yml" 2>/dev/null && return 0
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
local USE_ACTIONS=""
|
||||||
|
prompt_yn " Enable Gitea Actions (CI) with a local runner — runs .gitea/workflows/*.yml the same way GitHub Actions runs .github/workflows/*.yml, useful as a fallback if GitHub is ever unreachable? (y/n):" "n" USE_ACTIONS
|
||||||
|
[[ "$USE_ACTIONS" =~ ^[Yy]$ ]] || return 0
|
||||||
|
|
||||||
|
if ! grep -q 'GITEA__actions__ENABLED' "$DIR/docker-compose.yml"; then
|
||||||
|
log_info "Enabling Gitea Actions..."
|
||||||
|
sed -i '/GITEA__security__INSTALL_LOCK=true/a\ - GITEA__actions__ENABLED=true\n - GITEA__actions__DEFAULT_ACTIONS_URL=github' "$DIR/docker-compose.yml"
|
||||||
|
(cd "$DIR" && docker compose up -d) \
|
||||||
|
&& log_success "Actions enabled — Gitea restarted to apply." \
|
||||||
|
|| { log_warning "Restart failed — check: docker compose -f $DIR/docker-compose.yml logs"; return 1; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Generating a runner registration token..."
|
||||||
|
local RUNNER_TOKEN=""
|
||||||
|
RUNNER_TOKEN="$(docker exec -u git gitea gitea actions generate-runner-token 2>/dev/null | tail -1)"
|
||||||
|
if [[ -z "$RUNNER_TOKEN" ]]; then
|
||||||
|
log_warning "Couldn't generate a runner token automatically (older Gitea image?). Generate one by hand:"
|
||||||
|
log_warning " Gitea -> Site Administration -> Actions -> Runners -> Create new Runner"
|
||||||
|
log_warning " then add an act_runner container yourself using that token — see"
|
||||||
|
log_warning " https://docs.gitea.com/usage/actions/quickstart for the compose snippet."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$DIR/runner-data"
|
||||||
|
cat >> "$DIR/docker-compose.yml" << EOF
|
||||||
|
|
||||||
|
act_runner:
|
||||||
|
image: gitea/act_runner:latest
|
||||||
|
container_name: gitea-runner
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- GITEA_INSTANCE_URL=http://gitea:3000
|
||||||
|
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN}
|
||||||
|
- GITEA_RUNNER_NAME=gitea-runner
|
||||||
|
volumes:
|
||||||
|
- ./runner-data:/data
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
depends_on:
|
||||||
|
- gitea
|
||||||
|
EOF
|
||||||
|
|
||||||
|
_gitea_fix_ownership "$DIR"
|
||||||
|
(cd "$DIR" && docker compose up -d act_runner) \
|
||||||
|
&& log_success "Actions runner started — .gitea/workflows/*.yml will now run automatically on push." \
|
||||||
|
|| log_warning "Runner failed to start — check: docker compose -f $DIR/docker-compose.yml logs act_runner"
|
||||||
|
}
|
||||||
|
|
||||||
# ── Own systemd timer, not gitea-github-sync.sh's built-in --install-timer ──
|
# ── Own systemd timer, not gitea-github-sync.sh's built-in --install-timer ──
|
||||||
# The vendor script's own timer installer always runs the script bare (no
|
# The vendor script's own timer installer always runs the script bare (no
|
||||||
# --pull-only/--push-only), i.e. always both directions — there's no way to
|
# --pull-only/--push-only), i.e. always both directions — there's no way to
|
||||||
@@ -307,6 +438,8 @@ install_gitea() {
|
|||||||
echo "[DRY-RUN] Would ask sync direction (GitHub->Gitea / Gitea->GitHub / both) and whether"
|
echo "[DRY-RUN] Would ask sync direction (GitHub->Gitea / Gitea->GitHub / both) and whether"
|
||||||
echo "[DRY-RUN] to install a systemd timer for automatic sync, or print manual instructions"
|
echo "[DRY-RUN] to install a systemd timer for automatic sync, or print manual instructions"
|
||||||
echo "[DRY-RUN] Would offer to run a sync now (dry-run preview or for real), off-schedule"
|
echo "[DRY-RUN] Would offer to run a sync now (dry-run preview or for real), off-schedule"
|
||||||
|
echo "[DRY-RUN] Would offer \"Sign in with Authelia\" (OIDC) if Authelia is installed"
|
||||||
|
echo "[DRY-RUN] Would offer to enable Gitea Actions (CI) with a local act_runner container"
|
||||||
echo "[DRY-RUN] Would write $DIR/README.md"
|
echo "[DRY-RUN] Would write $DIR/README.md"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -333,6 +466,8 @@ install_gitea() {
|
|||||||
&& log_success "Gitea refreshed and restarted." \
|
&& log_success "Gitea refreshed and restarted." \
|
||||||
|| log_warning "Restart failed — check: docker compose -f $DIR/docker-compose.yml logs"
|
|| log_warning "Restart failed — check: docker compose -f $DIR/docker-compose.yml logs"
|
||||||
_gitea_run_sync_direction_step "$DIR"
|
_gitea_run_sync_direction_step "$DIR"
|
||||||
|
_gitea_offer_authelia_sso "$DIR"
|
||||||
|
_gitea_offer_actions_runner "$DIR"
|
||||||
log_success "Existing .env (tokens) and web/SSH ports were left untouched."
|
log_success "Existing .env (tokens) and web/SSH ports were left untouched."
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -494,9 +629,16 @@ ENV
|
|||||||
|
|
||||||
_gitea_run_sync_direction_step "$DIR"
|
_gitea_run_sync_direction_step "$DIR"
|
||||||
|
|
||||||
# ── Caddy (Gitea has its own built-in login — no Authelia needed) ──────
|
# ── Caddy — no forward_auth gate here. Gitea has its own built-in login,
|
||||||
|
# unlike the no-auth-at-all apps elsewhere in this repo that need Caddy
|
||||||
|
# to gate them via Authelia. Optional "Sign in with Authelia" (OIDC) is
|
||||||
|
# offered separately below, as an addition to Gitea's own login, not a
|
||||||
|
# replacement requiring Caddy involvement. ─────────────────────────────
|
||||||
configure_caddy_for_service "Gitea" "host.docker.internal:${WEB_PORT}" "git"
|
configure_caddy_for_service "Gitea" "host.docker.internal:${WEB_PORT}" "git"
|
||||||
|
|
||||||
|
_gitea_offer_authelia_sso "$DIR"
|
||||||
|
_gitea_offer_actions_runner "$DIR"
|
||||||
|
|
||||||
write_readme "$DIR" << MD
|
write_readme "$DIR" << MD
|
||||||
# Gitea
|
# Gitea
|
||||||
|
|
||||||
@@ -528,6 +670,27 @@ Config (which repos, private/forks handling) lives at
|
|||||||
\`~/.config/gitea-github-sync/config\` — edit directly, or re-run
|
\`~/.config/gitea-github-sync/config\` — edit directly, or re-run
|
||||||
\`bash gitea-github-sync.sh --init\` to redo it interactively.
|
\`bash gitea-github-sync.sh --init\` to redo it interactively.
|
||||||
|
|
||||||
|
## Sign in with Authelia (optional)
|
||||||
|
|
||||||
|
If Authelia is installed, re-run \`sudo ./setup.sh gitea\` (Update mode is
|
||||||
|
fine — this doesn't touch tokens or anything else) and answer yes to
|
||||||
|
"Add \"Sign in with Authelia\"?" to add it as an extra OAuth2 login option
|
||||||
|
on Gitea's own login page. Local admin login keeps working exactly as
|
||||||
|
before — this is additive, not a replacement. Managed in Gitea under
|
||||||
|
Site Administration -> Authentication Sources (source name: \`authelia\`).
|
||||||
|
|
||||||
|
## Gitea Actions (CI) — optional local runner
|
||||||
|
|
||||||
|
Re-run \`sudo ./setup.sh gitea\` (Update mode is fine) and answer yes to
|
||||||
|
"Enable Gitea Actions?" to run \`.gitea/workflows/*.yml\` here the same way
|
||||||
|
GitHub Actions runs \`.github/workflows/*.yml\` — mainly useful as a fallback
|
||||||
|
so builds still work if GitHub is ever unreachable. Adds an \`act_runner\`
|
||||||
|
container (\`docker compose ps\` will show \`gitea-runner\`) that polls this
|
||||||
|
Gitea instance for jobs and launches a fresh container per job using this
|
||||||
|
host's own Docker socket — same pattern already used by this repo's
|
||||||
|
portainer/watchtower/uptimekuma services, not something new. Manage runners
|
||||||
|
under Site Administration -> Actions -> Runners.
|
||||||
|
|
||||||
## Manage
|
## Manage
|
||||||
|
|
||||||
\`\`\`bash
|
\`\`\`bash
|
||||||
|
|||||||
Reference in New Issue
Block a user