For security reasons, accessing certain Object Storage Service (OSS) objects by using the default domain name of a bucket may trigger forced downloads or prohibit downloads. To preview or download these objects in a browser, you must map a custom domain name to the bucket and access the objects by using the custom domain name. Mapping a custom domain name does not affect the default domain name of the bucket, which can still be used to access OSS objects as usual.
Scenarios
Preview objects: For security reasons, when you access objects by using the default domain name of a bucket, OSS includes the headers that specify a forcible download in the response. This causes the browser to download the objects instead of previewing them. When you use a custom domain name to access the same objects, OSS does not include the headers that specify a forced download in the response. This enables the objects to be previewed directly in the browser instead of being downloaded. For more information about the effective time and objects that trigger automatic downloads when you access objects by using the default domain name of a bucket, see Appendix: x-oss-ec rules that trigger forcible downloads.
Access .apk or .ipa files: For security reasons, when you attempt to access .apk or .ipa files by using the default domain name of a bucket, OSS returns a 400 error with the error code ApkDownloadForbidden. However, access to the same objects by using a custom domain name is not restricted.
Brand image and professionalism: Mapping a custom domain name enhances your brand image and professionalism, increasing user trust.
Prevent domain blocking: Mapping a custom domain name helps avoid default domain blocking, ensuring normal access to resources.
Access convenience: Using a custom domain name to access OSS buckets is more convenient and facilitates resource sharing.
Link persistence: Mapping a custom domain name ensures link persistence, allowing continued access to resources even if storage locations change.
Limits
You cannot map a custom domain name that contains Chinese characters to a bucket.
Custom domain names that have already been mapped for image processing cannot be mapped to buckets again.
Each domain name can be mapped to only one bucket.
You can map up to 100 custom domain names to each bucket.
The OSS console does not support mapping a wildcard domain name to a bucket. For example, a domain name starting with an asterisk (*) cannot be mapped to a bucket. If such a domain name is mapped, all subdomains of that domain name will point to the bucket. However, when you use Alibaba Cloud CDN to accelerate access to a bucket, you can map a wildcard domain name to the bucket. However, the domain name is not displayed in the OSS console.
Prerequisites
A bucket is created.
A domain name is registered. You can map a domain name registered with a third-party provider to a bucket in Alibaba Cloud. If you do not have a domain name, we recommend that you register one by using the Alibaba Cloud Domains service platform.
An Internet Content Provider (ICP) filing is obtained for your domain name and real-name verification is complete for your Alibaba Cloud account if the bucket to which you want to map the domain name resides in the Chinese mainland. For more information about how to apply for an ICP filing and complete real-name verification, see ICP filing process, FAQ about real-name verification for Alibaba Cloud accounts.
Procedure
Step 1: Map a custom domain name
Based on the domain service provider (which can be queried on the Domain Information Query (WHOIS) page) and the account to which the domain belongs (which can be queried in the Alibaba Cloud DNS console), follow the corresponding steps to map the domain name to an OSS bucket.
Map a domain name registered by using the current Alibaba Cloud account
To map a custom domain name that is registered by using the current Alibaba Cloud account, perform the following steps:
Log on to the OSS console.
In the left-side navigation pane, click Buckets. On the Buckets page, find and click the desired bucket.
In the left-side navigation pane, choose Bucket Settings > Domain Names.
On the Domain Names page, click Map Custom Domain Name.
In the Map Custom Domain Name panel, enter a custom domain name without a protocol, such as
static.example.com
, and then click OK.Add a CNAME record to map the custom domain name
static.example.com
to the default public domain name of the bucket.Automatically add a CNAME record
In the Map Custom Domain Name panel, turn on Automatically Add CNAME Record.
After you turn on this option, Alibaba Cloud DNS automatically adds a CNAME record. Example:
Manually add a CNAME record
If you do not turn on Automatically Add CNAME Record in the Map Custom Domain Name panel, you must manually add a CNAME record in the Alibaba Cloud DNS console. Otherwise, the custom domain name that you mapped does not take effect.
Log on to the Alibaba Cloud DNS console.
In Public DNS > Authoritative Domain Names, click Configure in the Actions column corresponding to the target domain name.
Click Add Record and configure the domain name resolution information.
Parameter
Description
Example
Record Type
Select CNAME to points the domain name to the default domain name of the bucket.
CNAME
Host
The prefix of the domain.
static
ISP Line
The DNS line that is used to resolve the domain name. We recommend that you select Default. The system automatically selects the optimal line.
Default
Value
The public domain name of the bucket. The domain name of a bucket is in the <bucketname>.<endpoint> format. For more information about the public endpoints of different regions, see Regions and endpoints.
examplebucket.oss-cn-hangzhou.aliyuncs.com
TTL
The interval at which the record is updated. Keep the default value.
NoteThe TTL period setting may experience a delay before taking effect. The actual time in use will prevail.
10 minutes
Click OK.
After the configuration is complete, a CNAME record appears in Alibaba Cloud DNS. Example:
Map a domain name registered by using another Alibaba Cloud account
To map a custom domain name that is registered using Alibaba Cloud Account A to a bucket in Alibaba Cloud Account B, perform the following steps:
Use Alibaba Cloud Account B to obtain the hostname and value in the TXT record of the domain name.
Log on to the OSS console.
In the left-side navigation pane, click Buckets. On the Buckets page, find and click the desired bucket.
In the left-side navigation pane, choose Bucket Settings > Domain Names.
On the Domain Names page, click Map Custom Domain Name.
In the Map Custom Domain Name panel, enter the custom domain name of Alibaba Cloud Account A without a protocol, such as
static.example.com
, and then copy the Host Record and Record Value displayed on the page.
Use Alibaba Cloud Account A to add a TXT record.
Log on to the Alibaba Cloud DNS console.
In the domain name list, click Configure in the Actions column corresponding to the target domain name.
Click Add Record and configure the domain name resolution information.
Parameter
Description
Example
Record Type
The type of the DNS record that you want to add. In this topic, TXT is selected.
TXT
Host
The root domain is automatically filled. You do not need to manually enter the root domain part.
If you want to map a root domain name, enter
_dnsauth
. For example, if the domain name isexample.com
, enter_dnsauth
.If you want to map a subdomain name, enter
_dnsauth.<domain prefix>
. For example, if the domain name isstatic.example.com
, enter_dnsauth.static
.
_dnsauth.static
ISP Line
The DNS line that is used to resolve the domain name. We recommend that you select Default. The system automatically selects the optimal line.
Default
Value
The CnameToken of the TXT record that was recorded earlier by using Alibaba Cloud Account B.
b0d777f7ccddeae93358d908ed59****
TTL
The interval at which the record is updated. Keep the default value.
NoteThe TTL period setting may experience a delay before it takes effect. The actual time in use will prevail.
10 minutes
Click OK.
Use Alibaba Cloud Account B to click Verify Domain Name Ownership in the Map Custom Domain Name panel in the OSS console.
Use Alibaba Cloud Account A to add a CNAME record.
In the domain name list, click Configure in the Actions column corresponding to the target domain name.
Click Add Record and configure the domain name resolution information.
Parameter
Description
Example
Record Type
Select CNAME.
CNAME
Host
The host record based on the prefix of the domain name.
If the domain name is a root domain name, such as
example.com
, enter @.If the domain name is a subdomain name, enter the prefix of the subdomain name. For example, if the domain name is
static.example.com
, enter static.
static
ISP Line
The DNS line that is used to resolve the domain name. We recommend that you select Default. The system automatically selects the optimal line.
Default
Value
The public domain name of the bucket. The domain name of a bucket is in the <bucketname>.<endpoint> format. For more information about the public endpoints of different regions, see Regions and endpoints.
examplebucket.oss-cn-hangzhou.aliyuncs.com
TTL
The interval at which the record is updated. Keep the default value.
NoteThe TTL period setting may experience a delay before it takes effect. The actual time in use will prevail.
10 minutes
Click OK.
Map a custom domain name that is not registered using an Alibaba Cloud account
To map a domain name registered with a third-party provider to an OSS bucket, perform the following steps:
In the OSS console, generate a hostname and value as a TXT record for domain ownership verification.
Log on to the OSS console.
In the left-side navigation pane, click Buckets. On the Buckets page, find and click the desired bucket.
In the left-side navigation pane, choose Bucket Settings > Domain Names.
On the Domain Names page, click Map Custom Domain Name.
In the Map Custom Domain Name panel, enter the domain name registered with a third-party provider without a protocol, such as
static.example.com
, and then copy the Host Record and Value displayed on the page.
On the DNS platform of your domain provider, use the settings described in the following table to add a TXT record.
Parameter
Description
Example
Record type
The type of the DNS record that you want to add. Select TXT.
TXT
Hostname
If the DNS platform automatically fills in the root domain, you do not need to enter the root domain part.
If you want to map a root domain name, enter
_dnsauth
. For example, if the domain name isexample.com
, enter_dnsauth
.If you want to map a subdomain name, enter
_dnsauth.<domain prefix>
. For example, if the domain name isstatic.example.com
, enter_dnsauth.static
.
_dnsauth.static
Record value
The CnameToken of the TXT record that was recorded earlier from OSS.
b0d777f7ccddeae93358d908ed59****
In the Map Custom Domain Name panel in the OSS console, click Verify Domain Name Ownership.
On the DNS platform of your domain provider, use the settings described in the following table to add a CNAME record.
Parameter
Description
Example
Record type
The type of the DNS record that you want to add. Select CNAME.
CNAME
Hostname
The host record based on the prefix of the domain name.
If the domain name is a root domain name, such as
example.com
, enter @.If the domain name is a subdomain name, enter the prefix of the subdomain name. For example, if the domain name is
static.example.com
, enter static.
static
Record value
The public domain name of the bucket. The domain name of a bucket is in the <bucketname>.<endpoint> format. For more information about the public endpoints of different regions, see Regions and endpoints.
examplebucket.oss-cn-hangzhou.aliyuncs.com
Step 2: Verify the custom domain name
After you map a custom domain name to a bucket, any user request made by using the custom domain name will be resolved to the default domain name of the bucket through DNS. You can use the nslookup
or dig
command to verify whether the custom domain name resolution takes effect.
nslookup
Replace static.example.com
with the domain name that you want to query, and then run the following command.
nslookup -type=CNAME static.example.com
If the command output displays the public domain name of your bucket, the DNS records have taken effect.
dig
Replace static.example.com
with the domain name that you want to query, and then run the following command.
dig CNAME static.example.com
If the command output displays the public domain name of your bucket, the DNS records have taken effect.
Step 3: Use the custom domain name
After the custom domain name resolution takes effect, you can use the HTTP protocol and the custom domain name to construct a URL that includes a signature and an expiration time. The URL is in the http://YourDomain/ObjectName?signature parameters
format. You can use the URL to access OSS objects.
Generate a presigned URL.
Use the OSS console
Log on to the OSS console.
Click Buckets, and then click the name of the target bucket.
In the left-side navigation pane, choose
.On the Objects page, click the name of the object.
In the Details panel, select the custom domain name that you mapped from the Custom Domain Name drop-down list, keep other parameters at their default values, and then click Copy File URL.
Use ossbrowser
ossbrowser supports object-level operations similar to those supported by the OSS console. Follow the ossbrowser interface to generate a presigned URL. For more information about how to download ossbrowser, see ossbrowser 2.0 (Preview).
Use the custom domain name to log on to ossbrowser.
Obtain object URLs.
Use OSS SDKs
Use a custom domain name to create an OSSClient instance and generate a presigned URL.
Java
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import java.net.URL; import java.util.Date; public class Demo { public static void main(String[] args) throws Throwable { // Specify a custom domain name. Example: https://static.example.com. String endpoint = "yourCustomEndpoint"; // Specify the region in which the bucket is located. Example: cn-hangzhou. String region = "cn-hangzhou"; // Obtain access credentials from environment variables. Before you run the sample code, you must configure the environment variables. EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // Create an OSSClient instance. ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // To enable CNAME, set this parameter to true. clientBuilderConfiguration.setSupportCname(true); // Explicitly declare the use of the V4 signature algorithm. clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region(region) .build(); try { // Specify the validity period of the presigned URL. Unit: milliseconds. In this example, the validity period is 1 hour. Date expiration = new Date(new Date().getTime() + 3600 * 1000L); // Generate a presigned URL that allows HTTP GET requests. In this example, no additional request headers are specified. Other users can access the relevant content directly by using the browser. String bucketName = "examplebucket"; String objectName = "demo.png"; URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration); System.out.println(url); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } finally { if (ossClient != null) { ossClient.shutdown(); } } } }
Python
# -*- coding: utf-8 -*- import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider # Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # Specify the ID of the region that maps to the endpoint. Example: cn-hangzhou. This parameter is required if you use the signature algorithm V4. region = "cn-hangzhou" # Specify the custom domain name. Example: static.example.com. endpoint = 'http://static.example.com' # Specify the name of your bucket. bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region, is_cname=True) # Specify the full path of the object. Do not include the bucket name in the full path. Example: exampledir/exampleobject.txt. object_name = 'exampledir/exampleobject.txt' # Generate a presigned URL that is used to download the object. In this example, the validity period of the URL is 600 seconds. # By default, OSS identifies forward slashes (/) in the full path of an object as escape characters in the signing process. Therefore, the presigned URL cannot be directly used. # Set the slash_safe parameter to True. This way, OSS does not identify the forward slashes (/) in the full path of the object as escape characters, and the presigned URL can be directly used. url = bucket.sign_url('GET', object_name, 600, slash_safe=True, params=params) print('Presigned URL:', url)
Node.js
const OSS = require("ali-oss"); // Specify a function used to generate a presigned URL. async function generateSignatureUrl(fileName) { // Obtain the presigned URL. const client = await new OSS({ // Specify the custom domain name that you want to map to the bucket. endpoint: 'http://static.example.com', // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. accessKeyId: process.env.OSS_ACCESS_KEY_ID, accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET, bucket: 'examplebucket', // Specify the region in which the bucket is located. For example, if your bucket is located in the China (Hangzhou) region, set the region to oss-cn-hangzhou. region: 'oss-cn-hangzhou', authorizationV4: true, cname: true }); return await client.signatureUrlV4('GET', 3600, { headers: {} // Specify the request headers based on the actual request headers. }, fileName); } // Call the function and pass in the name of the object. generateSignatureUrl('yourFileName').then(url => { console.log('Generated Signature URL:', url); }).catch(err => { console.error('Error generating signature URL:', err); });
PHP
<?php if (is_file(__DIR__ . '/../autoload.php')) { require_once __DIR__ . '/../autoload.php'; } if (is_file(__DIR__ . '/../vendor/autoload.php')) { require_once __DIR__ . '/../vendor/autoload.php'; } use OSS\OssClient; use OSS\Core\OssException; use OSS\Http\RequestCore; use OSS\Http\ResponseCore; use OSS\Credentials\EnvironmentVariableCredentialsProvider; // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. $provider = new EnvironmentVariableCredentialsProvider(); // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to http://static.example.com. $endpoint = "http://static.example.com"; // Specify the name of the bucket. $bucket= "examplebucket"; // Specify the full path of the object. Do not include the bucket name in the full path. $object = "exampleobject.txt"; // Set the validity period of the presigned URL to 600 seconds. Maximum value: 32400. $timeout = 600; try { $config = array( "provider" => $provider, "endpoint" => $endpoint, 'signatureVersion'=>OssClient::OSS_SIGNATURE_VERSION_V4, "cname" => true, "region"=> "cn-hangzhou" ); $ossClient = new OssClient($config); // Generate a presigned URL. $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "GET"); print_r($signedUrl); } catch (OssException $e) { printf(__FUNCTION__ . ": FAILED\n"); printf($e->getMessage() . "\n"); return; }
Go
package main import ( "context" "flag" "log" "time" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials" ) // Specify the global variables. var ( region string // Region in which the bucket is located. bucketName string // Name of the bucket. objectName string // Name of the object. ) // Specify the init function used to initialize command line parameters. func init() { flag.StringVar(®ion, "region", "", "The region in which the bucket is located.") flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.") flag.StringVar(&objectName, "object", "", "The name of the object.") } func main() { // Parse command line parameters. flag.Parse() // Check whether the name of the bucket is specified. if len(bucketName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, bucket name required") } // Check whether the region is specified. if len(region) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, region required") } // Check whether the object is specified. if len(objectName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, object name required") } // Load the default configurations and specify the credential provider and region. cfg := oss.LoadDefaultConfig(). WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()). WithRegion(region). WithEndpoint("http://static.example.com"). WithUseCName(true) // Create an OSS client. client := oss.NewClient(cfg) // Generate a presigned URL for the GetObject request. result, err := client.Presign(context.TODO(), &oss.GetObjectRequest{ Bucket: oss.Ptr(bucketName), Key: oss.Ptr(objectName), //RequestPayer: oss.Ptr("requester"), // Specify the identity of the requester. }, oss.PresignExpires(10*time.Minute), ) if err != nil { log.Fatalf("failed to get object presign %v", err) } log.Printf("request method:%v\n", result.Method) log.Printf("request expiration:%v\n", result.Expiration) log.Printf("request url:%v\n", result.URL) if len(result.SignedHeaders) > 0 { // If you specify request headers when you generate a presigned URL that allows HTTP GET requests, make sure that the request headers are included in the GET request initiated by using the presigned URL. This prevents request failures and signature errors. log.Printf("signed headers:\n") for k, v := range result.SignedHeaders { log.Printf("%v: %v\n", k, v) } } }
Use ossutil
Use a custom domain name to generate a presigned URL for an object by using the presign command.
ossutil presign oss://examplebucket/exampleobject.txt --endpoint "http://static.example.com" --addressing-style "cname"
If you want ossutil to automatically use a custom domain name without manually specifying the custom domain name in each command, you can add the custom domain name to the configuration file.
Access the presigned URL in a browser.
Related API operations
For more information about the API operation that you can call to create a CnameToken for domain ownership verification, see CreateCnameToken.
For more information about the API operation that you can call to query a created CnameToken, see GetCnameToken.
For more information about the API operation that you can call to map a custom domain name to a bucket, see PutCname.
For more information about the API operation that you can call to query all custom domain names mapped to a bucket, see ListCname.
For more information about the API operation that you can call to delete a custom domain name mapped to a bucket, see DeleteCname.
For more information about the API operation that you can call to add a TXT record or a CNAME record by using Alibaba Cloud DNS, see AddDomainRecord - Add a DNS record based on input parameters.
What to do next
Access OSS objects over HTTPS
By default, access over HTTPS is not supported for a custom domain name if no SSL certificate is configured. When you attempt to access an object by using a custom domain name over HTTPS, the browser will display an insecure connection warning. To access OSS objects over HTTPS, configure an SSL certificate for the custom domain name.
Access OSS objects by using a permanent URL without a signature
To obtain a URL without a signature or an expiration time, which means that the URL is in the http://YourDomainName/ObjectName
format, you must set the ACL of the object to public-read. However, a public-read ACL allows any Internet user to access the object, which potentially leads to data leaks and increased costs. For enhanced security, we recommend that you use a URL that includes a signature and expiration time.
You can use one of the following methods to grant public-read access to an object:
Set the ACL of an object to public-read: Set the ACL of the OSS object to public-read. In this case, the object URL is permanently accessible to anyone. To prevent unauthorized use of your objects by other websites, you must configure hotlink protection for your bucket in OSS.
Use Alibaba Cloud CDN to accelerate access to OSS resources: Keep the ACL of the OSS object set to private and provide public-read access through CDN. In this case, the object URL is permanently accessible to anyone. To prevent unauthorized use of your objects by other websites, you must configure hotlink protection in CDN.
Prevent unauthorized use of OSS objects by other websites
By default, OSS objects can be accessed and displayed by any website. This can lead to unnecessary request and outbound traffic fees. You can configure hotlink protection to set a Referer whitelist or blacklist to limit access sources. After hotlink protection is enabled, unauthorized websites will be blocked from linking to your objects, and failed requests will not incur request fees and outbound traffic fees.
Use OSS to host static websites
If you use OSS as a server for a static website to store and provide static files such as HTML, CSS, and JavaScript files for users to access over the Internet, you must configure static website hosting for the bucket in addition to mapping a custom domain name to the bucket.
Enhance OSS object download speeds across regions
For example, if your OSS objects are stored in China (Hangzhou), you can use Alibaba Cloud CDN to accelerate access to OSS to improve the download speeds of the objects for users from different regions. When Alibaba Cloud CDN is enabled, OSS objects are cached at regional points of presence (POPs). Users accessing these objects are automatically routed to the nearest POP, ensuring faster and more efficient downloads.
We recommend that you use the CDN domain name for downloads to benefit from accelerated access and the default domain name of the bucket for uploads to optimize performance across regions.
Improve long-distance transmission speeds of OSS objects
For example, if your OSS objects are stored in China (Hangzhou), users accessing them from outside the Chinese mainland may encounter slow uploads and downloads. To improve the long-distance transmission speeds of OSS objects, you can enable transfer acceleration and map your custom domain name to the acceleration endpoint of OSS instead of the default domain name of the bucket.