GitHub Enterprise Server isn’t just a self-hosted GitHub; it’s a full-blown application cluster that needs careful planning and ongoing maintenance.

Let’s see it in action. Imagine you’ve just spun up a new GitHub Enterprise Server instance and you’re trying to onboard your first team. You’ve got your DNS records pointing to the load balancer, and your certificate is valid.

# /etc/github/enterprise.config
# Example configuration snippet
version: 2.22.0
hostname: github.yourcompany.com
mysql:
  host: 10.0.0.10
  port: 3306
  database: github_production
  username: github_user
  password: ${GH_MYSQL_PASSWORD}
redis:
  host: 10.0.0.11
  port: 6379
blob_storage:
  provider: s3
  bucket: github-enterprise-blobs
  region: us-east-1

This enterprise.config file is the heart of your GHES deployment. It tells the cluster where to find its dependencies (MySQL, Redis), how to store large objects (like Git blobs), and what hostname it will be known by. The actual application components—web servers, background workers, Git services—all read this configuration to know how to talk to each other and to external services. When you initialize GHES, it uses this config to set up its internal databases, caches, and storage.

The core problem GHES solves is providing a robust, on-premises Git hosting solution with all the collaboration features of GitHub.com, but under your direct control. This means you can integrate it deeply with your internal identity providers (like Active Directory or Okta), enforce specific security policies, and ensure data residency.

Internally, GHES is a distributed system. It typically runs on a cluster of virtual or physical machines. A load balancer distributes incoming HTTP/S traffic to multiple web frontends. These frontends interact with a shared MySQL database for metadata (users, repositories, issues, etc.) and Redis for caching. Git operations themselves are handled by specialized Git services, which also rely on the blob storage for large file data. Background jobs, responsible for tasks like rendering READMEs, processing webhooks, and running CI/CD pipelines (if you’re using GitHub Actions within GHES), run on separate worker nodes.

You manage GHES primarily through the Admin Console, accessible via http(s)://your-ghe-hostname.com/login. Here, you can configure authentication, manage licenses, monitor system health, and perform administrative tasks. For deeper configuration or troubleshooting, you’ll SSH into the appliance and interact with files like enterprise.config or use command-line tools.

The levers you control are vast:

  • Authentication: SAML, LDAP, OAuth, built-in user management.
  • Networking: IP addresses, hostnames, SSL certificates, firewall rules.
  • Storage: Configuring object storage (S3, Azure Blob Storage, NFS) for Git blobs and LFS.
  • High Availability: Setting up redundant nodes, database replication.
  • Backups: Configuring automated backups to an external location.
  • GitHub Actions: Enabling and configuring self-hosted runners.
  • Integrations: Setting up webhooks, OAuth applications, and API access.

When GitHub Actions is enabled, each runner effectively becomes a small, ephemeral worker that pulls jobs from the GHES instance, executes them in a sandboxed environment, and reports status back. The runners themselves need to be able to reach the GHES API endpoint and have network access to any internal resources required by the jobs.

One common point of confusion is how GHES handles internal network traffic versus external. For instance, if your GHES instance is configured to use an internal load balancer for external access, but your GitHub Actions runners are deployed on a separate network segment that can only reach the internal IP of the GHES frontends, you might encounter connectivity issues if the runners try to resolve the external hostname. The runners must be able to resolve and connect to the same network endpoint that users use to access the web interface, or be configured with specific internal routing to reach the GHES cluster directly. This often involves ensuring DNS resolution is consistent across all internal networks where runners might be provisioned.

The next major hurdle after getting GHES operational is often integrating it with your CI/CD pipelines and managing the lifecycle of your self-hosted GitHub Actions runners.

Want structured learning?

Take the full Github course →