diff --git a/api/handler/api.go b/api/handler/api.go
index 559977aa6..6ef460bab 100644
--- a/api/handler/api.go
+++ b/api/handler/api.go
@@ -41,6 +41,7 @@ type (
 		RetryMaxAttempts() int
 		RetryMaxBackoff() time.Duration
 		RetryStrategy() RetryStrategy
+		TLSTerminationHeader() string
 	}
 
 	FrostFSID interface {
diff --git a/api/handler/attributes.go b/api/handler/attributes.go
index 22ceffb49..4e4a9132c 100644
--- a/api/handler/attributes.go
+++ b/api/handler/attributes.go
@@ -98,7 +98,7 @@ func (h *handler) GetObjectAttributesHandler(w http.ResponseWriter, r *http.Requ
 	}
 	info := extendedInfo.ObjectInfo
 
-	encryptionParams, err := formEncryptionParams(r)
+	encryptionParams, err := h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
diff --git a/api/handler/copy.go b/api/handler/copy.go
index 00473fa99..f4c8c783c 100644
--- a/api/handler/copy.go
+++ b/api/handler/copy.go
@@ -103,12 +103,12 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
 	}
 	srcObjInfo := extendedSrcObjInfo.ObjectInfo
 
-	srcEncryptionParams, err := formCopySourceEncryptionParams(r)
+	srcEncryptionParams, err := h.formCopySourceEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
 	}
-	dstEncryptionParams, err := formEncryptionParams(r)
+	dstEncryptionParams, err := h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
diff --git a/api/handler/get.go b/api/handler/get.go
index 11b877033..3403ac7da 100644
--- a/api/handler/get.go
+++ b/api/handler/get.go
@@ -202,7 +202,7 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	encryptionParams, err := formEncryptionParams(r)
+	encryptionParams, err := h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
diff --git a/api/handler/handlers_test.go b/api/handler/handlers_test.go
index e5a224b93..42db0eb02 100644
--- a/api/handler/handlers_test.go
+++ b/api/handler/handlers_test.go
@@ -141,6 +141,10 @@ func (c *configMock) RetryStrategy() RetryStrategy {
 	return RetryStrategyConstant
 }
 
+func (c *configMock) TLSTerminationHeader() string {
+	return "X-Frostfs-TLS-Termination"
+}
+
 func prepareHandlerContext(t *testing.T) *handlerContext {
 	hc, err := prepareHandlerContextBase(layer.DefaultCachesConfigs(zap.NewExample()))
 	require.NoError(t, err)
diff --git a/api/handler/head.go b/api/handler/head.go
index 314adfe21..8556e4b70 100644
--- a/api/handler/head.go
+++ b/api/handler/head.go
@@ -51,7 +51,7 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
 	}
 	info := extendedInfo.ObjectInfo
 
-	encryptionParams, err := formEncryptionParams(r)
+	encryptionParams, err := h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
diff --git a/api/handler/multipart_upload.go b/api/handler/multipart_upload.go
index bb1092752..730148531 100644
--- a/api/handler/multipart_upload.go
+++ b/api/handler/multipart_upload.go
@@ -138,7 +138,7 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
 		}
 	}
 
-	p.Info.Encryption, err = formEncryptionParams(r)
+	p.Info.Encryption, err = h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err, additional...)
 		return
@@ -223,7 +223,7 @@ func (h *handler) UploadPartHandler(w http.ResponseWriter, r *http.Request) {
 		ContentSHA256Hash: r.Header.Get(api.AmzContentSha256),
 	}
 
-	p.Info.Encryption, err = formEncryptionParams(r)
+	p.Info.Encryption, err = h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err, additional...)
 		return
@@ -323,7 +323,7 @@ func (h *handler) UploadPartCopy(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	srcEncryptionParams, err := formCopySourceEncryptionParams(r)
+	srcEncryptionParams, err := h.formCopySourceEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
@@ -348,7 +348,7 @@ func (h *handler) UploadPartCopy(w http.ResponseWriter, r *http.Request) {
 		Range:         srcRange,
 	}
 
-	p.Info.Encryption, err = formEncryptionParams(r)
+	p.Info.Encryption, err = h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err, additional...)
 		return
@@ -593,7 +593,7 @@ func (h *handler) ListPartsHandler(w http.ResponseWriter, r *http.Request) {
 		PartNumberMarker: partNumberMarker,
 	}
 
-	p.Info.Encryption, err = formEncryptionParams(r)
+	p.Info.Encryption, err = h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
@@ -629,7 +629,7 @@ func (h *handler) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Req
 		Key:      reqInfo.ObjectName,
 	}
 
-	p.Encryption, err = formEncryptionParams(r)
+	p.Encryption, err = h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
diff --git a/api/handler/put.go b/api/handler/put.go
index 5d9974360..cb2456733 100644
--- a/api/handler/put.go
+++ b/api/handler/put.go
@@ -228,7 +228,7 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
 		metadata[api.ContentLanguage] = contentLanguage
 	}
 
-	encryptionParams, err := formEncryptionParams(r)
+	encryptionParams, err := h.formEncryptionParams(r)
 	if err != nil {
 		h.logAndSendError(ctx, w, "invalid sse headers", reqInfo, err)
 		return
@@ -363,15 +363,15 @@ func (h *handler) getBodyReader(r *http.Request) (io.ReadCloser, error) {
 	return chunkReader, nil
 }
 
-func formEncryptionParams(r *http.Request) (enc encryption.Params, err error) {
-	return formEncryptionParamsBase(r, false)
+func (h *handler) formEncryptionParams(r *http.Request) (enc encryption.Params, err error) {
+	return h.formEncryptionParamsBase(r, false)
 }
 
-func formCopySourceEncryptionParams(r *http.Request) (enc encryption.Params, err error) {
-	return formEncryptionParamsBase(r, true)
+func (h *handler) formCopySourceEncryptionParams(r *http.Request) (enc encryption.Params, err error) {
+	return h.formEncryptionParamsBase(r, true)
 }
 
-func formEncryptionParamsBase(r *http.Request, isCopySource bool) (enc encryption.Params, err error) {
+func (h *handler) formEncryptionParamsBase(r *http.Request, isCopySource bool) (enc encryption.Params, err error) {
 	var sseCustomerAlgorithm, sseCustomerKey, sseCustomerKeyMD5 string
 	if isCopySource {
 		sseCustomerAlgorithm = r.Header.Get(api.AmzCopySourceServerSideEncryptionCustomerAlgorithm)
@@ -387,7 +387,17 @@ func formEncryptionParamsBase(r *http.Request, isCopySource bool) (enc encryptio
 		return
 	}
 
-	if r.TLS == nil {
+	needCheckTLS := true
+	if tlsTerminationStr := r.Header.Get(h.cfg.TLSTerminationHeader()); len(tlsTerminationStr) > 0 {
+		tlsTermination, err := strconv.ParseBool(tlsTerminationStr)
+		if err != nil {
+			h.reqLogger(r.Context()).Warn(logs.WarnInvalidTypeTLSTerminationHeader, zap.Error(err))
+		} else {
+			needCheckTLS = !tlsTermination
+		}
+	}
+
+	if needCheckTLS && r.TLS == nil {
 		return enc, apierr.GetAPIError(apierr.ErrInsecureSSECustomerRequest)
 	}
 
diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go
index 01986eed4..7af302bb2 100644
--- a/cmd/s3-gw/app.go
+++ b/cmd/s3-gw/app.go
@@ -129,6 +129,7 @@ type (
 		retryStrategy                 handler.RetryStrategy
 		tombstoneMembersSize          int
 		tombstoneLifetime             uint64
+		tlsTerminationHeader          string
 	}
 
 	maxClientsConfig struct {
@@ -316,6 +317,7 @@ func (s *appSettings) update(v *viper.Viper, log *zap.Logger) {
 	httpLoggingUseGzip := v.GetBool(cfgHTTPLoggingGzip)
 	tombstoneMembersSize := fetchTombstoneMembersSize(v)
 	tombstoneLifetime := fetchTombstoneLifetime(v)
+	tlsTerminationHeader := v.GetString(cfgSSECTLSTerminationHeader)
 
 	s.mu.Lock()
 	defer s.mu.Unlock()
@@ -347,6 +349,7 @@ func (s *appSettings) update(v *viper.Viper, log *zap.Logger) {
 	s.vhsNamespacesEnabled = vhsNamespacesEnabled
 	s.tombstoneMembersSize = tombstoneMembersSize
 	s.tombstoneLifetime = tombstoneLifetime
+	s.tlsTerminationHeader = tlsTerminationHeader
 }
 
 func (s *appSettings) prepareVHSNamespaces(v *viper.Viper, log *zap.Logger, defaultNamespaces []string) map[string]bool {
@@ -541,6 +544,12 @@ func (s *appSettings) RetryStrategy() handler.RetryStrategy {
 	return s.retryStrategy
 }
 
+func (s *appSettings) TLSTerminationHeader() string {
+	s.mu.RLock()
+	defer s.mu.RUnlock()
+	return s.tlsTerminationHeader
+}
+
 func (s *appSettings) AccessBoxContainer() (cid.ID, bool) {
 	if s.accessbox != nil {
 		return *s.accessbox, true
diff --git a/cmd/s3-gw/app_settings.go b/cmd/s3-gw/app_settings.go
index edf876912..1650b6b33 100644
--- a/cmd/s3-gw/app_settings.go
+++ b/cmd/s3-gw/app_settings.go
@@ -59,9 +59,10 @@ const (
 
 	defaultAccessBoxCacheRemovingCheckInterval = 5 * time.Minute
 
-	defaultNamespaceHeader  = "X-Frostfs-Namespace"
-	defaultVHSHeader        = "X-Frostfs-S3-VHS"
-	defaultServernameHeader = "X-Frostfs-Servername"
+	defaultNamespaceHeader      = "X-Frostfs-Namespace"
+	defaultVHSHeader            = "X-Frostfs-S3-VHS"
+	defaultServernameHeader     = "X-Frostfs-Servername"
+	defaultTLSTerminationHeader = "X-Frostfs-TLS-Termination"
 
 	defaultMultinetFallbackDelay = 300 * time.Millisecond
 
@@ -280,6 +281,9 @@ const ( // Settings.
 	// Server.
 	cfgReconnectInterval = "reconnect_interval"
 
+	// SSE-C.
+	cfgSSECTLSTerminationHeader = "sse_c.tls_termination_header"
+
 	// envPrefix is an environment variables prefix used for configuration.
 	envPrefix = "S3_GW"
 )
@@ -946,6 +950,9 @@ func newSettings() *viper.Viper {
 	// multinet
 	v.SetDefault(cfgMultinetFallbackDelay, defaultMultinetFallbackDelay)
 
+	// sse-c
+	v.SetDefault(cfgSSECTLSTerminationHeader, defaultTLSTerminationHeader)
+
 	// Bind flags
 	if err := bindFlags(v, flags); err != nil {
 		panic(fmt.Errorf("bind flags: %w", err))
diff --git a/config/config.env b/config/config.env
index 44a897159..986cfdf65 100644
--- a/config/config.env
+++ b/config/config.env
@@ -269,3 +269,6 @@ S3_GW_MULTINET_FALLBACK_DELAY=300ms
 # List of subnets and IP addresses to use as source for those subnets
 S3_GW_MULTINET_SUBNETS_1_MASK=1.2.3.4/24
 S3_GW_MULTINET_SUBNETS_1_SOURCE_IPS=1.2.3.4 1.2.3.5
+
+# Header for determining the termination of TLS.
+S3_GW_SSE_C_TLS_TERMINATION_TLS_HEADER=X-Frostfs-TLS-Termination
diff --git a/config/config.yaml b/config/config.yaml
index 8f1694638..a4fc23820 100644
--- a/config/config.yaml
+++ b/config/config.yaml
@@ -318,3 +318,6 @@ multinet:
       source_ips:
         - 1.2.3.4
         - 1.2.3.5
+
+sse_c:
+  tls_termination_header: X-Frostfs-TLS-Termination
diff --git a/docs/configuration.md b/docs/configuration.md
index 0f98747f4..99ebaf2e6 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -196,6 +196,7 @@ There are some custom types used for brevity:
 | `containers`       | [Containers configuration](#containers-section)                |
 | `vhs`              | [VHS configuration](#vhs-section)                              |
 | `multinet`         | [Multinet configuration](#multinet-section)                    |
+| `sse_c`            | [SSE-C configuration](#sse_c-section)                          |
 
 ### General section
 
@@ -681,7 +682,7 @@ web:
 
 | Parameter             | Type       | SIGHUP reload | Default value | Description                                                                                                                                                                                  |
 |-----------------------|------------|---------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `read_timeout`        | `duration` | no            | `0`           | The maximum duration for reading the entire	request, including the body. A zero or negative value means there will be no timeout.                                                            |
+| `read_timeout`        | `duration` | no            | `0`           | The maximum duration for reading the entire	request, including the body. A zero or negative value means there will be no timeout.                                                           |
 | `read_header_timeout` | `duration` | no            | `30s`         | The amount of time allowed to read request headers. If `read_header_timeout` is zero, the value of `read_timeout` is used. If both are zero, there is no timeout.                            |
 | `write_timeout`       | `duration` | no            | `0`           | The maximum duration before timing out writes of the response. A zero or negative value means there will be no timeout.                                                                      |
 | `idle_timeout`        | `duration` | no            | `30s`         | The maximum amount of time to wait for the next request when keep-alives are enabled. If `idle_timeout` is zero, the value of `read_timeout` is used. If both are zero, there is no timeout. |
@@ -858,3 +859,16 @@ multinet:
 |--------------|------------|---------------|---------------|----------------------------------------------------------------------|
 | `mask`       | `string`   | yes           |               | Destination subnet.                                                  |
 | `source_ips` | `[]string` | yes           |               | Array of source IP addresses to use when dialing destination subnet. |
+
+# `sse_c` section
+
+Configuration of SSE-C.
+
+```yaml
+sse_c:
+  tls_termination_header: X-Frostfs-TLS-Termination
+```
+
+| Parameter                | Type     | SIGHUP reload | Default value               | Description                                                                                                                                                                                                               |
+| ------------------------ | -------- | ------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `tls_termination_header` | `string` | yes           | `X-Frostfs-TLS-Termination` | The header for determining whether TLS needs to be checked. If the system requests come through a proxy server and TLS can terminate at the proxy level, you should use this header to disable TLS verification at SSE-C. |
diff --git a/internal/logs/logs.go b/internal/logs/logs.go
index 0c47ef451..1070b91a6 100644
--- a/internal/logs/logs.go
+++ b/internal/logs/logs.go
@@ -181,4 +181,5 @@ const (
 	FailedToPutTombstoneObject                           = "failed to put tombstone object"
 	FailedToCreateWorkerPool                             = "failed to create worker pool"
 	FailedToListAllObjectRelations                       = "failed to list all object relations"
+	WarnInvalidTypeTLSTerminationHeader                  = "invalid type of value of tls termination header"
 )