VPS Snaps

How to use Google Cloud Storage for server backups

To back up servers to Google Cloud Storage, create a regional bucket with uniform bucket-level access and public access prevention, give a dedicated service account only Storage Object Creator and Storage Object Viewer on it, and upload with gcloud storage cp or rclone. Keep the default 7-day soft delete, add a lifecycle rule that deletes old backups, and add a retention policy if backups must survive a stolen key. Every storage class, Archive included, reads back in milliseconds.

10 min readUpdated Checked against official documentation

Create the bucket

Choose the location first: changing it later needs bucket relocation, a paid Storage Intelligence feature.

Location typeRedundancyPrice
Region, such as us-central1Synchronous across zones in one regionLowest storage price, no replication charge
Dual-regionAsynchronous across two regionsHighest storage price, replication charge on writes
Multi-region: us, eu, asiaAsynchronous across regions in a large areaBetween the two; replication charge on writes, and reads always count as data transfer

Google lists regions and dual-regions for backup and archive; a region away from your servers is the cheaper choice:

Terminal
gcloud storage buckets create gs://acme-server-backups --project=acme-backups --location=us-central1 --default-storage-class=STANDARD --uniform-bucket-level-access --public-access-prevention
  • Names: 3 to 63 lowercase letters, numbers, dashes, underscores and dots, with no goog prefix and no google. They are global and public, so keep anything identifying out.
  • --location: without it, the bucket lands in the us multi-region. --default-storage-class applies to uploads that don't name a class.
  • --uniform-bucket-level-access: no ACLs, only IAM. gcloud leaves it off without the flag, and after 90 days it can't be turned off.
  • --public-access-prevention: grants to allUsers and allAuthenticatedUsers fail.
  • Soft delete is on by default for 7 days; --soft-delete-duration sets 7 to 90 days, or 0 for off. Encryption at rest is automatic.

Choose a storage class

Class (API name)Minimum storage durationRetrieval feeStorage in `us-central1`
Standard (STANDARD)NoneNone$0.020 per GiB-month
Nearline (NEARLINE)30 days$0.01 per GiB$0.010 per GiB-month
Coldline (COLDLINE)90 days$0.02 per GiB$0.004 per GiB-month
Archive (ARCHIVE)365 days$0.05 per GiB$0.0012 per GiB-month

Prices as of October 2026. Unlike S3 Glacier Flexible Retrieval or Deep Archive, every class is online: Archive objects download in milliseconds. Deleting or replacing an object before its minimum duration bills the remaining days. Use Standard for backups kept under 30 days and Nearline for 30 days or more.

Give the server a narrow service account

A role granted on a bucket covers every object in it, so give each server its own service account, and its own bucket if servers mustn't read each other's backups.

RoleAllowsDoesn't allow
Storage Object Creator (roles/storage.objectCreator)Creating objects, aborting multipart uploadsViewing, listing, deleting or overwriting objects
Storage Object Viewer (roles/storage.objectViewer)Reading and listing objectsAny write
Storage Object User (roles/storage.objectUser)Creating, reading, deleting and restoring objectsObject IAM or retention
Storage Object Admin (roles/storage.objectAdmin)All object actions, including IAM policies and retentionBucket settings

Creator plus Viewer is the backup pair: the server can upload and read back, but can't delete or overwrite anything. A lifecycle rule does the pruning.

Terminal
gcloud iam service-accounts create web01-backup --display-name="web-01 backups"
Terminal
gcloud storage buckets add-iam-policy-binding gs://acme-server-backups --member=serviceAccount:[email protected] --role=roles/storage.objectCreator

Run the second command again with --role=roles/storage.objectViewer.

Get credentials onto the server

On Compute Engine, attach the account to the VM with the cloud-platform scope; programs on the VM then use it without a key file. The default scopes make Cloud Storage read-only, so uploads fail even when IAM is right. Changing them needs the VM stopped:

Terminal
gcloud compute instances set-service-account web-01 --zone=us-central1-a --service-account=web01-backup@acme-backups.iam.gserviceaccount.com --scopes=cloud-platform

Anywhere else, the simple route is a JSON key, created where you're logged in as an admin:

Terminal
gcloud iam service-accounts keys create web01-backup.json [email protected]

Copy it to the server as /root/web01-backup.json, chmod 600 it, delete your local copy, and run gcloud auth activate-service-account --key-file=/root/web01-backup.json on the server.

A key file is a password with no second factor that never expires by default: whoever copies it is the service account until you delete the key. Organizations created on or after May 3, 2024 block key creation by default. Workload Identity Federation avoids keys for workloads on AWS or Azure, behind an OIDC or SAML identity provider, or holding X.509 client certificates, at the cost of more setup.

Upload with gcloud storage cp

Terminal
gcloud storage cp /var/backups/web-01-2026-10-04.tar.gz gs://acme-server-backups/web-01/2026-10-04.tar.gz

gcloud storage validates hashes on upload and download. Use dated names: Object Creator can't overwrite, so a repeated name fails instead of replacing a backup. To stream without a temporary file, use - as the source:

Terminal
tar -czf - /etc /var/www | gcloud storage cp - gs://acme-server-backups/web-01/2026-10-04-files.tar.gz

--storage-class=NEARLINE overrides the default for one upload. Build the archive with tar and schedule it with cron. Skip gsutil in new scripts: Google calls it legacy, it doesn't support soft delete, and after March 2027 it ships only on PyPI, outside the Google Cloud CLI.

Use rclone's Google Cloud Storage backend

~/.config/rclone/rclone.conf
[gcs]
type = google cloud storage
service_account_file = /root/web01-backup.json
bucket_policy_only = true
no_check_bucket = true
  • type = google cloud storage is the native backend, not Google Drive. bucket_policy_only = true is required with uniform bucket-level access, which rclone knows by its old name, Bucket Policy Only.
  • no_check_bucket = true skips checking or creating the bucket, which these roles can't do.
  • On Compute Engine, use env_auth = true instead of service_account_file.
Terminal
rclone copy /var/backups/web-01/ gcs:acme-server-backups/web-01/

copy lists the destination first, so the account needs Object Viewer too. Cloud Storage stores MD5 hashes, so rclone check can compare them. See rclone backups.

S3 tools: the XML API and HMAC keys

The XML API at https://storage.googleapis.com accepts S3-style V4 signatures made with an HMAC key, so many S3 tools work with a new endpoint and the region auto, as in Google's samples:

Terminal
gcloud storage hmac create [email protected]

It prints an access ID starting with GOOG and a secret shown once. In rclone's S3 backend, use provider = GCS and endpoint = https://storage.googleapis.com. Documented differences from S3:

  • HMAC keys work only with the XML API, at most 10 per service account, and a new one can take 60 seconds to work.
  • x-amz-* headers count only where an x-goog-* equivalent exists; storage classes use Cloud Storage names such as NEARLINE.
  • Listing or creating buckets needs a default project under Settings > Interoperability, or an x-amz-project-id header.
  • Multipart uploads: 10,000 parts of 5 MiB to 5 GiB, objects up to 5 TiB, a CRC32C but no MD5. Unfinished parts are billed until aborted.
  • Object holds can't be managed through it, and the restrictAuthTypes organization policy can block HMAC keys.

Expire old backups with a lifecycle rule

lifecycle.json
{
  "lifecycle": {
    "rule": [
      {
        "action": { "type": "Delete" },
        "condition": { "age": 30, "matchesPrefix": ["web-01/"] }
      },
      {
        "action": { "type": "AbortIncompleteMultipartUpload" },
        "condition": { "age": 7 }
      }
    ]
  }
}
Terminal
gcloud storage buckets update gs://acme-server-backups --lifecycle-file=lifecycle.json
  • age: 30 counts days from upload; the deleted backup then spends the soft delete window there, billed.
  • matchesPrefix takes prefixes without the bucket name.
  • AbortIncompleteMultipartUpload clears unfinished XML API uploads; it accepts only age, matchesPrefix and matchesSuffix.
  • The file replaces the whole lifecycle configuration. Changes take up to 24 hours, and actions run asynchronously.

Soft delete or Object Versioning

Soft delete keeps deleted and overwritten objects for its window; they can't be read, only listed and restored, and are billed like live data. Google recommends it over Object Versioning against accidental or malicious deletion, since it also covers deleted buckets. Versioning keeps readable old versions instead and needs a daysSinceNoncurrentTime rule to prune them.

Terminal
gcloud storage ls 'gs://acme-server-backups/web-01/**' --soft-deleted
Terminal
gcloud storage restore gs://acme-server-backups/web-01/2026-10-04.tar.gz

Restoring needs storage.objects.restore, which Storage Object Admin has and the backup account doesn't; restored objects land in Standard. Changing the soft delete policy is a bucket update, which no object role includes.

Retention policies and object holds

A bucket retention policy blocks deleting or replacing any object younger than the period, existing objects included:

Terminal
gcloud storage buckets update gs://acme-server-backups --retention-period=P14D
  • Unlocked, it can be shortened or removed. --lock-retention-period makes it permanent: it can only grow, the bucket can't be deleted until every object meets it, and a lien blocks deleting the project.
  • Keep it shorter than the lifecycle age, or backups stay billed until it passes.
  • Holds pin one object with no end date: gcloud storage objects update gs://acme-server-backups/web-01/2026-10-04.tar.gz --temporary-hold.
  • Object Retention Lock sets a retain-until time per object, in buckets created with --enable-per-object-retention or switched on later in the console.

Locking a retention policy can't be undone. Test with an unlocked policy and a short period first.

Verify a backup

Terminal
gcloud storage ls -l gs://acme-server-backups/web-01/
Terminal
gcloud storage cp gs://acme-server-backups/web-01/2026-10-04.tar.gz /tmp/restore-test.tar.gz && sha256sum /tmp/restore-test.tar.gz && tar -tzf /tmp/restore-test.tar.gz > /dev/null && echo OK

Compare the hash with one recorded before upload; gcloud storage hash and gcloud storage objects describe give the CRC32C and MD5 of local and stored copies. See testing a restore.

What it costs

  • Storage by class and location, as above; soft-deleted, noncurrent and unfinished multipart data is billed too.
  • Operations in one region, Standard: Class A (uploads, listings) $0.005 and Class B (reads) $0.0004 per 1,000; colder classes cost more. Deletes are free.
  • Data in is free. Internet egress is $0.12 per GiB for the first 10 TiB a month, more to China and Australia.
  • Always Free: 5 GB-months of Standard, 5,000 Class A and 50,000 Class B operations in us-east1, us-west1 and us-central1, and 100 GB of transfer from North America (Australia and China excluded).

Example, at October 2026 prices: 30 daily 5 GiB backups under the rule above keep about 150 GiB live plus 35 GiB in soft delete. In us-central1, before Always Free, that is about $3.70 a month in Standard or $1.85 in Nearline. After the free transfer, pulling one backup to a server outside Google costs about $0.60, plus $0.05 retrieval from Nearline.

Common errors

ErrorCause and fix
409 Conflict. Sorry, that name is not available. Please try a different one.Bucket names are global; pick another.
403 Account Disabled when creating a bucketBilling isn't enabled on the project.
... doesn't have storage.objects.get access to the Google Cloud Storage object.A missing role, or the wrong credentials if it names an unexpected account or Anonymous caller. Check gcloud auth list.
A 403 on a Compute Engine VM whose IAM looks rightThe default read-only Storage scope. Stop the VM and set --scopes=cloud-platform.
403 - retentionPolicyNotMetDeleting or replacing an object younger than the retention period.
FAILED_PRECONDITION: Key creation is not allowed on this service account.The iam.disableServiceAccountKeyCreation organization policy. Use the VM's account, an HMAC key, or ask for an exception.
SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. (rclone S3 backend)Cloud Storage altered headers on a gzip request. Set --s3-use-accept-encoding-gzip=false.

For backups an attacker can't remove, see protecting backups from ransomware; to keep them unreadable to anyone else, encrypt them before upload.

Frequently asked questions

Is Google Cloud Storage S3-compatible?
Partly. The XML API at https://storage.googleapis.com accepts S3-style requests signed with an HMAC key, but HMAC keys don't work with the JSON API and some S3 headers and features differ, so test your tool first.
Does Archive storage take hours to restore?
No. Every Cloud Storage class, Archive included, is online and returns data in milliseconds. Archive charges a $0.05 per GiB retrieval fee and has a 365-day minimum storage duration, as of October 2026.
Is soft delete on by default in Cloud Storage?
Yes. New buckets keep deleted and overwritten objects for 7 days, billed like live data. You can set 7 to 90 days, or 0 to turn it off.
Can the Storage Object Creator role delete files?
No. It can create objects but not view, list, delete or overwrite them. Add Storage Object Viewer if the server must read backups back.

How this was checked

Commands, limits and prices were checked against these official pages, on October 4, 2026: