---
title: "HTTP Upload"
weight: 190
---

GoReleaser supports building and pushing artifacts to HTTP servers using simple
HTTP requests.

## How it works

You can declare multiple `uploads` instances. All binaries generated by your
`builds` section will be pushed to each configured upload.

If you have only one `uploads` instance, the configuration is as easy as adding
the upload target and a name to your `.goreleaser.yaml` file:

```yaml
uploads:
  - name: production
    target: http://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/
```

Prerequisites:

- An HTTP server accepting HTTP requests
- A user + password / client x509 certificate / API key with grants to upload an artifact

> [!NOTE]
> authentication is optional and may be provided if the server requires it
>
> - user/pass is for Basic Authentication
> - client x509 certificate is for mutual TLS authentication (aka "mTLS")

### Target

The `target` is the template of the URL to upload the artifacts to (_without_ the name of the artifact).

An example configuration for `goreleaser` in upload mode `binary` with the target can look like:

```yaml
- name: production
  mode: binary
  target: "http://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}"
```

And will result in an HTTP PUT request sent to
`http://some.server/some/path/example-repo-local/goreleaser/1.0.0/Darwin/x86_64/goreleaser`.

Supported variables:

- `Version`
- `Tag`
- `ProjectName`
- `ArtifactName`
- `Os`
- `Arch`
- `Arm`

> [!WARNING]
> Variables `Os`, `Arch` and `Arm` are only supported in upload mode `binary`.

For `archive` mode, it will also included the `LinuxPackage` type which is
generated by `nfpm` and the like.

### Username

Your configured username needs to be valid against your HTTP server.

You can have the username set in the configuration file as shown above
or you can have it read from an environment variable.
The configured name of your HTTP server will be used to build the environment
variable name.
This way we support auth for multiple instances.
This also means that the `name` per configured instance needs to be unique
per GoReleaser configuration.

The name of the environment variable will be `UPLOAD_NAME_USERNAME`.
If your instance is named `production`, you can store the username in the
environment variable `UPLOAD_PRODUCTION_USERNAME`.
The name will be transformed to uppercase.

If a configured username is found in the configuration file, then the
environment variable is not used at all.

This field is optional and is used only for basic http authentication.

### Password

The password will be stored in an environment variable.
The configured name of your HTTP server will be used.
This way we support auth for multiple instances.
This also means that the `name` per configured instance needs to be unique
per GoReleaser configuration.

The name of the environment variable will be `UPLOAD_NAME_SECRET`.
If your instance is named `production`, you need to store the secret in the
environment variable `UPLOAD_PRODUCTION_SECRET`.
The name will be transformed to uppercase.

This field is optional and is used only for basic http authentication.

### Client authorization with x509 certificate (mTLS / mutual TLS)

If your artifactory server supports authorization with mTLS (client
certificates), you can provide them by specifying the location of an x509
certificate/key pair of pem-encode files.

```yaml
uploads:
  - name: production
    client_x509_cert: path/to/client.cert.pem
    client_x509_key: path/to/client.key.pem
    target: "http://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}"
```

This will offer the client certificate during the TLS handshake, which your artifactory server may use to authenticate
and authorize you to upload.

### Server authentication

You can authenticate your TLS server adding a trusted X.509 certificate chain in
your upload configuration.

The trusted certificate chain will be used to validate the server certificates.

You can set the trusted certificate chain using the `trusted_certificates`
setting the upload section with PEM encoded certificates on a YAML literal block
like this:

```yaml
uploads:
  - name: "some HTTP/TLS server"
    #...(other settings)...
    trusted_certificates: |
      -----BEGIN CERTIFICATE-----
      MIIDrjCCApagAwIBAgIIShr2zchZo+8wDQYJKoZIhvcNAQENBQAwNTEXMBUGA1UE
      ...(edited content)...
      TyzMJasj5BPZrmKjJb6O/tOtEIJ66xPSBTxPShkEYHnB7A==
      -----END CERTIFICATE-----
      -----BEGIN CERTIFICATE-----
      MIIDrjCCApagAwIBAgIIShr2zchZo+8wDQYJKoZIhvcNAQENBQAwNTEXMBUGA1UE
      ...(edited content)...
      TyzMJasj5BPZrmKjJb6O/tOtEIJ66xPSBTxPShkEYHnB7A==
      -----END CERTIFICATE-----
```

## Customization

Of course, you can customize a lot of things:

```yaml {filename=".goreleaser.yaml"}
uploads:
  # You can have multiple upload instances.
  - # Unique name of your upload instance. Used to identify the instance.
    name: production

    # HTTP method to use.
    #
    # Default: 'PUT'.
    method: POST

    # IDs of the artifacts you want to upload.
    ids:
      - foo
      - bar

    # File extensions to filter for.
    # This might be useful if you have multiple packages with different
    # extensions with the same ID, and need to upload each extension to
    # a different place (e.g. nFPM packages).
    exts:
      - deb
      - rpm

    # Matrix will run the upload for each possible combination of the given
    # values.
    # The keys will be available as template variables in the `target` and
    # `custom_headers` fields.
    #
    # This feature is only available in GoReleaser Pro.
    matrix:
      foo: [bar zaz]
      something: [foobar somethingelse anotherthing]

    # Upload mode. Valid options are `binary` and `archive`.
    #
    # If mode is `archive`, variables _Os_, _Arch_ and _Arm_ for target name
    #   are not supported. In that case these variables are empty.
    #
    # If mode is `binary`, you'll need to have the archives section setup with
    #   format "binary" as well.
    #
    # Default: 'archive'.
    mode: archive

    # URL to be used as target of the HTTP request
    #
    # Templates: allowed.
    target: https://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/

    # Custom artifact name.
    # If enable, you must supply the name of the Artifact as part of the Target
    # URL as it will not be automatically append to the end of the URL, its
    # pre-computed name is available as _ArtifactName_ for example
    # target: https://some.server/some/path/example-repo-local/{{ .ArtifactName }};deb.distribution=xenial
    custom_artifact_name: true

    # An optional username that will be used for the deployment for basic auth.
    #
    # Templates: allowed. {{< g_inline_version "v2.12" >}}
    username: deployuser

    # An optional password that will be used for the deployment for basic auth.
    #
    # Templates: allowed.
    # {{< g_inline_version "v2.12" >}}
    password: '{{ readFile "~/.config/foo" }}'

    # Client certificate and key (when provided, added as client cert to TLS connections)
    client_x509_cert: /path/to/client.cert.pem
    client_x509_key: /path/to/client.key.pem

    # An optional header you can use to tell GoReleaser to pass the artifact's
    # SHA256 checksum within the upload request.
    checksum_header: -X-SHA256-Sum

    # A map of custom headers e.g. to support required content types or auth schemes.
    custom_headers:
      JOB-TOKEN: "{{ .Env.CI_JOB_TOKEN }}"

    # Upload checksums.
    checksum: true

    # Upload metadata.json and artifacts.json.
    meta: true

    # Upload signatures.
    signature: true

    # Skip this upload configuration.
    #
    # Templates: allowed.
    # {{< g_inline_version "v2.7" >}}
    skip: "{{gt .Patch 0}}"

    # Certificate chain used to validate server certificates
    trusted_certificates: |
      -----BEGIN CERTIFICATE-----
      MIIDrjCCApagAwIBAgIIShr2zchZo+8wDQYJKoZIhvcNAQENBQAwNTEXMBUGA1UE
      ...(edited content)...
      TyzMJasj5BPZrmKjJb6O/tOtEIJ66xPSBTxPShkEYHnB7A==
      -----END CERTIFICATE-----

    # You can add extra pre-existing files to the upload.
    #
    # The filename on the release will be the last part of the path (base).
    # If another file with the same name exists, the last one found will be used.
    # These globs can also include templates.
    #
    # {{< g_inline_version "v2.1" >}}
    extra_files:
      - glob: ./path/to/file.txt
      - glob: ./docs/*.md
      - glob: ./glob/**/to/**/file/**/*
      - glob: ./glob/foo/to/bar/file/foobar/override_from_previous
      - glob: ./single_file.txt
        # Templates: allowed.
        # Note that this only works if glob matches exactly 1 file.
        name_template: file.txt

    # Additional templated extra files to uploaded.
    # Those files will have their contents pass through the template engine,
    # and its results will be uploaded.
    #
    # {{< g_inline_pro >}}
    # {{< g_inline_version "v2.1" >}}
    # Templates: allowed.
    templated_extra_files:
      - src: LICENSE.tpl
        dst: LICENSE.txt

    # Upload only the files defined in extra_files.
    #
    # {{< g_inline_version "v2.1" >}}
    extra_files_only: true
```

{{< g_featpro >}}

These settings should allow you to push your artifacts into multiple HTTP
servers.

## GitLab generic package registry

You can use the HTTP upload pipe to publish your artifacts to a [GitLab
generic package
registry](https://docs.gitlab.com/user/packages/generic_packages/):

```yaml {filename=".goreleaser.yaml"}
uploads:
  - name: gitlab
    target: https://gitlab.com/api/v4/projects/<project>/packages/generic/{{ .ProjectName }}/{{ .Version }}/
    custom_headers:
      PRIVATE-TOKEN: "{{ .Env.REGISTRY_TOKEN }}"
```

`<project>` is either the project ID or the URL-encoded path of the project
(e.g. `mygroup%2Freleases`). The registry can belong to any project you can
write to — including a project other than the one being released, which allows
you to [store all of your packages in one GitLab
project](https://docs.gitlab.com/user/packages/workflows/project_registry/).

The token needs the `write_package_registry` scope (project or group [access
tokens](https://docs.gitlab.com/user/project/settings/project_access_tokens/),
[deploy tokens](https://docs.gitlab.com/user/project/deploy_tokens/), and
personal access tokens are all supported). Use the `DEPLOY-TOKEN` header for
deploy tokens, or, when running in GitLab CI/CD with a [job
token](https://docs.gitlab.com/ci/jobs/ci_job_token/) that has access to the
target project, `JOB-TOKEN: "{{ .Env.CI_JOB_TOKEN }}"`.

If you only want the artifacts in the registry and not attached to the release
of the project being built, you can also set `release.skip_upload: true`.

{{< g_templates >}}
