A self-hosted GitHub Enterprise Server (GHES) instance holds your source code, Actions secrets and deploy keys, and the customer operates every layer of it: the Management Console, the administrative shell, the network ports, the upgrade cycle and the backups. With GitHub.com most of the platform is run for you; with GHES the appliance is yours to configure, patch and watch. This guide covers the appliance and enterprise administration layer: how identity and administrator rights work, how to control the root site administrator, Management Console operators and SSH admin access on port 122, how to stream the audit log, and a hardening baseline covering TLS, private mode, subdomain isolation, upgrades and backups. It is written for GHES administrators, platform engineers and the security teams who review them. Organisation and repository settings, branch protection and Actions hardening are covered in the GitHub and GitHub Actions Security Guide and are not repeated here. Checked against the GHES 3.22 documentation.
This is an independent guide from NHI Mgmt Group, based on GitHub's public documentation as of November 2026. It is not sponsored or reviewed by GitHub. Product features change, so confirm settings against GitHub's current documentation.
Key takeaways
- There are two administrative planes. The Management Console (port 8443) and the administrative shell (SSH on port 122) control the appliance itself, while site administrators and enterprise owners control users, organisations and policies in the web application; protect both.
- SSH keys in the Management Console are root-level access. Any operator can add a key that grants the admin shell, so treat every key as a privileged credential with an owner and a review date.
- Your identity provider can decide who is an admin. Unless "Disable administrator demotion/promotion" is selected, SAML assertions control site administrator rights, so the IdP group behind that claim is as sensitive as the admin role itself.
- Patching is a customer task with a clear window. GitHub supports at least the four most recent feature releases and ships patch releases more often; hotpatches usually avoid a full outage, so there is little reason to fall behind.
- Stream the audit log off the box. Audit and Git events can be streamed to Amazon S3, Azure Blob Storage, Azure Event Hubs, Datadog, Google Cloud Storage or Splunk, with a daily health check and a six-day window to fix a broken stream.
How identity and access work in GitHub Enterprise Server
GHES separates authentication for the web application from access to the appliance. End users sign in to the application through one authentication method chosen by the administrator: built-in authentication, CAS, LDAP or SAML. Appliance administration uses its own credentials, set during initial setup, which do not pass through your identity provider.
SAML single sign-on
SAML is the usual choice for organisations with a central identity provider. The GHES SAML settings worth reviewing are:
- Require encrypted assertions: lets the instance receive encrypted assertions. The IdP must support encryption, the encryption and key transport methods must match on both sides, and you give the IdP the instance's public certificate.
- Signature and digest methods: two settings choose the hashing algorithms used to verify requests from the instance. Pick SHA-256 or stronger where your IdP supports it.
- Allow built-in authentication: lets people without an account in your IdP sign in with a local username and password. Leave it off unless you have a documented need, such as a small number of contractor accounts, because those accounts sit outside your IdP's MFA and lifecycle controls.
- Disable administrator demotion/promotion: stops the SAML provider from deciding administrator rights. Leave it cleared if you want IdP group membership to drive admin rights (and then govern that group tightly), or select it if you want admin rights managed only on the instance.
SCIM provisioning is supported for certain identity providers; with SCIM, user roles are managed in the IdP, which gives you joiner, mover and leaver automation. See the SAML Security Guide and the SCIM Provisioning Guide for protocol-level hardening.
LDAP
Where LDAP sync is used, the Administrators group attribute matters: every member of that directory group automatically receives site administrator access. Review the membership of that group as part of privileged access reviews.
Admin roles and privileged access
GHES has four distinct kinds of privileged access. They are managed in different places, so inventory them separately.
| Role or access | Where it is managed | What it can do | Key control |
|---|---|---|---|
| Root site administrator | Management Console, password set at initial setup | Full control of the Management Console, including creating and deleting Management Console user accounts | Long random password in a vault, used only for break-glass and user administration |
| Management Console users (operators) | Management Console, created by the root site administrator via invitation link | Most basic appliance tasks, including adding SSH keys that grant the admin shell; cannot create or delete console accounts | Named accounts per person, no shared operators, quarterly review |
| Administrative shell (SSH) | SSH keys added in the Management Console, user admin, port 122 | Troubleshooting and documented operations using ghe-* commands, such as promoting users or resetting passwords | Restrict port 122 to admin networks, one key per person, remove keys on leave |
| Site administrators and enterprise owners | Enterprise settings > People > Administrators, or ghe-user-promote; may be driven by SAML or LDAP | Manage users, organisations, enterprise policies and other administrators | Small named group, IdP group governed, MFA at the IdP |
Controlling the Management Console
The root site administrator should create named Management Console accounts for each operator rather than share the root password. GitHub states that only the root site administrator can create and delete Management Console accounts, which keeps operator sprawl in check. Configure the console's login rate limiting: set a maximum number of failed attempts and a lockout time in minutes. Saving these settings restarts system services, so plan it for a quiet period. If the root login locks, someone with SSH access can run ghe-reactivate-admin-login; a forgotten root password is reset with ghe-set-password. Both commands show why SSH access is effectively the top privilege on the appliance.
Controlling SSH admin access
Administrative SSH listens on port 122 (port 22 is Git over SSH for end users). Keys are added in the Management Console under SSH access and take effect immediately. GitHub describes the admin shell as being for troubleshooting and documented operations only, and warns that modifying system files or installing unsupported software can void support. Practical controls:
- Network: allow port 122 and port 8443 only from a management subnet or privileged access workstations. Port 122 must also be open between all high availability nodes.
- Keys: one key per administrator, labelled with the owner's name, generated on a managed device and ideally hardware-backed. Remove keys on role change or departure.
- Change control: record each shell session against a ticket, since many
ghe-*commands change users or configuration directly.
See the Privileged Access Management Guide and the Break-Glass Account Guide for vaulting and emergency access patterns.
Site administrators
Site administrators can promote and demote other administrators, either in Enterprise settings or with ghe-user-promote and ghe-user-demote from the shell. Keep the group small, require that every promotion has a ticket, and alert on promotions (see Logging and detection). ghe-org-admin-promote promotes users to organisation owner and deserves the same scrutiny.
Integrations, API tokens and service accounts
Most non-human access to GHES arrives through tokens and keys, not people. The appliance adds a few credential types of its own on top of the usual GitHub ones.
| Credential | Typical use | Recommended practice |
|---|---|---|
| Personal access tokens (PATs) | Scripts, CLI use, legacy integrations | Prefer fine-grained tokens with an expiry, set enterprise token policies, review unused tokens |
| GitHub Apps | CI/CD, bots, third-party tools | Preferred for automation: short-lived installation tokens, scoped permissions, owned by an organisation |
| Deploy keys and user SSH keys | Read or write access to single repositories | Read-only by default, named per system, removed when the system retires |
| Machine user accounts | Legacy automation that needs a seat | Replace with GitHub Apps where possible; otherwise an owner, MFA and no admin rights |
| Audit log streaming credentials | S3 keys, Azure SAS URLs, Event Hubs connection strings, Splunk HEC tokens, GCS service account keys | Write-only permissions to the destination, stored and rotated like any other secret |
| Management Console SSH keys | Backup and monitoring hosts, admin automation | Dedicated key per host, restricted source IP, inventory entry with owner |
Two points are specific to GHES. First, the streaming destinations need credentials that live on the appliance: the S3 option needs an access key with s3:PutObject on a bucket with public access blocked, and the Google Cloud Storage option needs a service account JSON key with the Storage Object Creator role. Scope these to write-only and record them in your secrets inventory. Second, Actions on GHES often uses self-hosted runners with network reach into internal systems, which makes runner registration tokens and runner host credentials part of the appliance's blast radius. See the GitHub Personal Access Tokens Security Guide, How to audit GitHub Apps and OAuth apps in an organisation and How to find unused GitHub deploy keys and SSH keys.
Logging and detection
GHES records enterprise activity in an audit log that is retained indefinitely unless an enterprise owner sets a different retention period. The web view shows the past three months by default; older events need a date range with the created qualifier. Two export routes exist, and most organisations use both:
- Audit log streaming: sends audit events and Git events for all organisations in the enterprise, from the moment the stream is enabled, to Amazon S3, Azure Blob Storage, Azure Event Hubs, Datadog, Google Cloud Storage or Splunk (HTTP Event Collector). Delivery is at-least-once, so expect occasional duplicates. A health check runs every 24 hours, enterprise owners are emailed if a stream is misconfigured, and the stream must be fixed within six days to avoid dropped events.
- Log forwarding: forwards audit and system logs to a third-party monitoring system, which covers appliance-level activity that the application audit log does not.
Events worth alerting on
| Activity | Why it matters | Suggested response |
|---|---|---|
| Site administrator or organisation owner promotion | Direct privilege escalation | Page on any promotion without a matching change ticket |
| Management Console SSH key added | Grants the admin shell | Alert immediately and confirm with the key owner |
| Authentication method or SAML settings changed | Could open built-in login or shift admin control | Treat as a high-severity change |
| Audit log stream disabled or failing | Loss of visibility | Act on the health check email within the six-day window |
| Repository visibility changed to public or internal | Possible data exposure | Review against data classification |
| Large clone or download volume by one token | Possible bulk exfiltration of code (MITRE ATT&CK T1213.003, Code Repositories) | Investigate the token owner and source IP |
Use of valid stolen credentials (ATT&CK T1078, Valid Accounts) is the most likely route to an internal code platform, so correlate GHES sign-ins with IdP risk signals. See the GitHub Audit Log Detection Guide for event names and query patterns, and the GitHub Organisation Compromise Playbook for response.
Metrics
- Release currency: days between a GHES patch release and its installation on production.
- Admin footprint: number of site administrators, Management Console users and admin SSH keys, each with a named owner.
- Stream health: hours of audit stream downtime per quarter.
- Restore confidence: date of the last successful test restore to a staging instance.
- Token hygiene: percentage of PATs with an expiry and percentage of automation using GitHub Apps.
Hardening baseline
Network and transport
The GHES port reference lists the ports below. Expose only what each audience needs.
| Port | Service | Audience | Baseline |
|---|---|---|---|
| 443 / 80 | Web and Git over HTTPS; HTTP redirects to HTTPS when TLS is configured | Users | Open to users; keep 80 only for the redirect |
| 22 | Git over SSH | Users | Open to users |
| 9418 | Unencrypted Git protocol for public repositories | Users | Close unless anonymous Git read is a deliberate choice |
| 8443 | Management Console over HTTPS | Admins | Management network only |
| 8080 | Management Console over plain HTTP | Admins | Close; only needed if TLS is manually disabled |
| 122 | Administrative SSH | Admins and HA nodes | Management network and HA peers only |
| 1194/UDP | High availability replication tunnel | HA nodes | Between nodes only |
| 161/UDP | SNMP | Monitoring | Monitoring hosts only; prefer SNMPv3 where used |
| 25 | Inbound SMTP with STARTTLS | Mail relay | Only if inbound email is used |
Within the Harden security settings, configure:
- TLS: install a certificate from a trusted certificate authority and restrict TLS and SSH cipher suites to meet your cryptographic standard.
- Host keys and SSH connections: choose the algorithms used for host keys and the algorithms clients may use to connect.
- Private mode: requires every user to sign in before seeing anything on the instance. Turn it on for any instance holding internal code.
- Subdomain isolation: separates user-supplied content from the rest of the appliance, which reduces cross-site scripting risk. It needs wildcard DNS and a matching certificate, so plan it at build time.
- Referrer policy: limits what the instance discloses in cross-origin requests.
Patching and upgrades
GitHub ships feature releases roughly quarterly and patch releases more often, and states that it supports at least the four most recent feature releases. The release list in the GHES documentation shows a closing down date for each version (for example, 3.19 closes on 9 December 2026 and 3.22 on 8 September 2027, as listed in November 2026). Patch releases can be applied as a hotpatch or an upgrade package; feature releases need an upgrade package. Hotpatches require a configuration run that can briefly cause errors, and sometimes a reboot that can be deferred. A sound routine:
- Subscribe: watch the GHES release notes, which list security fixes for each patch release, and set an internal target such as 14 days for security patches.
- Plan the path: use GitHub's Upgrade assistant to find the supported path from your current version.
- Back up first: take a recent successful backup snapshot of the primary node. For a feature release also take a VM or disk snapshot immediately before upgrading, after maintenance mode is on or the instance is powered down.
- Stage: apply the release to a staging instance restored from production backup and run smoke tests for sign-in, Git push and Actions.
- Apply: enable maintenance mode with an IP exception list so administrators can check health, apply the package or hotpatch, then check the replica.
- Roll back if needed: restore from the disk snapshot or backup, then delete pre-upgrade snapshots once the upgrade is confirmed.
Apply vendor security updates promptly. See the Patch Management Guide for setting service levels.
Backups and high availability
GHES now includes a built-in backup service, managed from the Management Console, which writes timestamped snapshots to a dedicated storage volume; the older backup utilities run on a separate host. GitHub is explicit that a high availability replica does not replace backups, because replication can copy corruption or data loss to the replica. Keep backups on storage the appliance's own administrators cannot delete, encrypt them at rest, and restore to a staging instance at least quarterly. See the Backup Security and Immutable Backup Guide.
Common misconfigurations
- Shared root console password: several engineers use the root site administrator login, so console changes cannot be attributed. Create named operator accounts and vault the root password.
- Orphaned admin SSH keys: keys added for a migration, a vendor or a departed engineer remain in the Management Console. Review the key list monthly against the admin roster.
- Management ports reachable from user networks: 8443 and 122 are open to the same networks as 443. Move them behind a management network or firewall rule.
- Built-in authentication left on beside SAML: local accounts escape IdP MFA and offboarding. Turn off "Allow built-in authentication" or keep a short, reviewed list.
- Unchecked IdP admin claim: admin rights follow a broad IdP group nobody reviews. Govern that group or select "Disable administrator demotion/promotion".
- Running a release near its closing down date: upgrades slip until a security patch requires a feature upgrade under pressure. Track closing down dates on the release list and schedule feature upgrades each quarter.
Framework mapping
| GHES control | NIST SP 800-53 Rev 5 | NIST CSF 2.0 | ISO/IEC 27001:2022 Annex A |
|---|---|---|---|
| SAML SSO, SCIM, admin role governance | IA-2, AC-2, AC-6 | PR.AA-05 | A.5.15, A.8.2 |
| Port restriction, SSH admin access | AC-17, CM-7 | PR.AA-05 | A.8.20 |
| TLS, ciphers, private mode | SC-8, CM-6 | PR.PS-01 | A.8.9, A.8.24 |
| Patching and upgrades | SI-2 | PR.PS-02 | A.8.8 |
| Audit log streaming and forwarding | AU-2, AU-6, AU-9 | PR.PS-04, DE.CM-09 | A.8.15, A.8.16 |
| Backups and restore tests | CP-9 | PR.DS-11 | A.8.13 |
Practitioner checklist
- Vault the root site administrator password and create a named Management Console account for each operator.
- Set Management Console login rate limiting with a failed-attempt limit and lockout time.
- Restrict ports 8443 and 122 to a management network and close 8080 and, unless needed, 9418.
- Inventory admin SSH keys, site administrators and LDAP or IdP admin groups, each with an owner, and review them monthly.
- Turn on private mode and subdomain isolation, install a trusted TLS certificate and restrict TLS and SSH ciphers.
- Decide whether SAML controls admin rights, and either govern the IdP group or select "Disable administrator demotion/promotion".
- Stream audit and Git events to your SIEM or storage with write-only credentials, and act on stream health emails.
- Stay within the four most recent feature releases and apply security patch releases within your service level.
- Back up with the built-in backup service or backup utilities to protected storage and test a restore each quarter.
- Move automation from PATs and machine users to GitHub Apps where possible.
Standards and references
- GitHub Docs: Hardening security for your enterprise (GHES)
- GitHub Docs: Network ports (GHES)
- GitHub Docs: Managing access to the Management Console
- GitHub Docs: Configuring SAML single sign-on for your enterprise (GHES)
- GitHub Docs: Streaming the audit log for your enterprise (GHES)
- GitHub Docs: Overview of the upgrade process (GHES)
- GitHub Docs: GitHub Enterprise Server releases
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls
Related NHI Mgmt Group resources: GitHub and GitHub Actions Security Guide · GitHub Audit Log Detection Guide · GitHub Organisation Security Checklist · Privileged Access Management Guide