Skip to content

Self-hosted Providers

updater.zig supports self-hosted Git hosting solutions including Gitea, Forgejo, and GitLab.

Self-hosted Gitea/Forgejo

Create a provider for your Gitea or Forgejo instance:

zig
const myGitea = updater.providers.gitea("https://git.mycompany.com");

const result = try updater.checkForUpdates(allocator, .{
    .provider = myGitea,
    .owner = "team",
    .repo = "project",
    .current_version = "1.0.0",
});

API Endpoint

GET {base_url}/api/v1/repos/{owner}/{repo}/releases/latest

Compatible Platforms

  • Gitea
  • Forgejo
  • Gogs
  • OneDev (with Gitea API compatibility)

Self-hosted GitLab

Create a provider for your GitLab instance:

zig
const myGitlab = updater.providers.selfHostedGitlab("https://gitlab.mycompany.com");

const result = try updater.checkForUpdates(allocator, .{
    .provider = myGitlab,
    .owner = "group",
    .repo = "project",
    .current_version = "1.0.0",
});

API Endpoint

GET {base_url}/api/v4/projects/{owner}%2F{repo}/releases/permalink/latest

Authentication

Self-hosted instances often require authentication:

Gitea/Forgejo Token

zig
fn createAuthGitea(base_url: []const u8, token: []const u8) updater.GitProvider {
    const static_headers = struct {
        var headers: [3]updater.HttpHeader = undefined;
        var token_value: [256]u8 = undefined;
    };

    const token_header = std.fmt.bufPrint(
        &static_headers.token_value,
        "token {s}",
        .{token},
    ) catch "token ";

    static_headers.headers = .{
        .{ .name = "Accept", .value = "application/json" },
        .{ .name = "User-Agent", .value = "updater.zig/0.0.1" },
        .{ .name = "Authorization", .value = token_header },
    };

    return updater.providers.custom(
        "gitea-auth",
        buildGiteaUrl,
        parseGiteaResponse,
        &static_headers.headers,
    );
}

GitLab Token

zig
fn createAuthGitlab(base_url: []const u8, token: []const u8) updater.GitProvider {
    // Similar pattern with PRIVATE-TOKEN header
}

Configuration Example

Complete example for a self-hosted setup:

zig
const std = @import("std");
const updater = @import("updater");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Create provider for internal Git server
    const internal_git = updater.providers.gitea("https://git.internal.corp");

    const result = try updater.checkForUpdates(allocator, .{
        .enabled = true,
        .provider = internal_git,
        .owner = "engineering",
        .repo = "core-lib",
        .current_version = "2.5.0",
        .timeout_ms = 5000,  // Internal network, quick timeout
    });

    if (result.has_update) {
        std.debug.print("Internal update available: {s}\n", .{result.latest_version.?});
    }
}

SSL/TLS Considerations

Self-hosted instances may use:

  • Self-signed certificates
  • Internal CA certificates
  • Custom certificate chains

The HTTP client will validate certificates. For testing, ensure your CA is trusted by the system.

Firewall Considerations

Ensure your build/runtime environment can reach:

  • The Git server hostname
  • The API port (usually 443 for HTTPS)

Troubleshooting

Connection Refused

  • Server not running
  • Firewall blocking connection
  • Wrong port

SSL Error

  • Certificate not trusted
  • Certificate chain incomplete
  • Hostname mismatch

401 Unauthorized

  • Token invalid or expired
  • Token lacks required permissions

404 Not Found

  • Wrong base URL
  • Repository path incorrect
  • No releases exist

Released under the MIT License.