• Home
  • Cloud VPS
    • Hong Kong VPS
    • US VPS
  • Dedicated Servers
    • Hong Kong Servers
    • US Servers
    • Singapore Servers
    • Japan Servers
  • Company
    • Contact Us
    • Blog
logo logo
  • Home
  • Cloud VPS
    • Hong Kong VPS
    • US VPS
  • Dedicated Servers
    • Hong Kong Servers
    • US Servers
    • Singapore Servers
    • Japan Servers
  • Company
    • Contact Us
    • Blog
ENEN
  • 简体简体
  • 繁體繁體
Client Area

Self-Hosted Object Storage on Hong Kong VPS: MinIO S3-Compatible (2026)

September 13, 2026

MinIO is the leading open-source S3-compatible object storage server — the same API as Amazon S3, but running entirely on your Hong Kong VPS. Applications that use the AWS SDK, S3 browser tools, or any S3-compatible client work with MinIO without code changes. You eliminate AWS egress fees, keep data in Hong Kong’s jurisdiction, and give mainland Chinese applications fast access to stored objects via CN2 GIA routing rather than routing through US S3 endpoints.


Use Cases

  • User-uploaded files (profile photos, documents, attachments)
  • Application media storage (product images, videos)
  • Database and VPS backups (replace off-site backup destinations)
  • Static website assets served directly from MinIO
  • Docker image layers (with MinIO as registry backend)
  • Log archival and data lake storage

Step 1: Deploy MinIO

<code">mkdir -p /opt/minio/{data,config}

# Single-node deployment (suitable for most use cases)
docker run -d \
  --name minio \
  --restart unless-stopped \
  -p 127.0.0.1:9000:9000 \     # S3 API endpoint
  -p 127.0.0.1:9001:9001 \     # MinIO Console (web UI)
  -v /opt/minio/data:/data \
  -e MINIO_ROOT_USER=admin \
  -e MINIO_ROOT_PASSWORD=StrongMinioPassword! \
  -e MINIO_BROWSER_REDIRECT_URL=https://storage-console.yourdomain.com \
  quay.io/minio/minio server /data \
    --console-address ":9001"

docker logs minio | tail -10

Step 2: Nginx with SSL for S3 API and Console

<code">cat > /etc/nginx/sites-available/minio << 'EOF'
# S3 API endpoint — used by applications
server {
    listen 443 ssl http2;
    server_name storage.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/storage.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/storage.yourdomain.com/privkey.pem;

    # Allow large uploads (adjust for your max file size)
    client_max_body_size 5G;
    client_body_timeout 300s;
    proxy_request_buffering off;   # Stream directly to MinIO

    ignore_invalid_headers off;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
        proxy_buffering off;
    }
}

# Admin console — restrict access
server {
    listen 443 ssl http2;
    server_name storage-console.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/storage-console.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/storage-console.yourdomain.com/privkey.pem;

    # Restrict to admin IPs
    allow YOUR_OFFICE_IP;
    deny all;

    location / {
        proxy_pass http://127.0.0.1:9001;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
EOF

certbot --nginx -d storage.yourdomain.com -d storage-console.yourdomain.com
nginx -t && systemctl reload nginx

Step 3: Create Buckets and Access Policies

<code"># Install MinIO client
wget https://dl.min.io/client/mc/release/linux-amd64/mc -O /usr/local/bin/mc
chmod +x /usr/local/bin/mc

# Configure mc to connect to your MinIO instance
mc alias set hkminio https://storage.yourdomain.com admin StrongMinioPassword!

# Create buckets
mc mb hkminio/app-uploads        # User uploads
mc mb hkminio/app-media          # Product images, videos
mc mb hkminio/backups            # Database backups (private)
mc mb hkminio/logs               # Log archival (private)

# Make media bucket public (read-only)
mc anonymous set download hkminio/app-media

# Create application user with limited permissions
mc admin user add hkminio app-user StrongAppUserPass!
mc admin policy attach hkminio readwrite --user app-user

# Or create a fine-grained policy:
cat > /tmp/app-policy.json << 'POLICY'
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
            "Resource": ["arn:aws:s3:::app-uploads/*", "arn:aws:s3:::app-media/*"]
        },
        {
            "Effect": "Allow",
            "Action": ["s3:ListBucket"],
            "Resource": ["arn:aws:s3:::app-uploads", "arn:aws:s3:::app-media"]
        }
    ]
}
POLICY

mc admin policy create hkminio app-policy /tmp/app-policy.json
mc admin policy attach hkminio app-policy --user app-user

Step 4: Use with AWS SDK (Drop-in Replacement)

Node.js

<code"># npm install @aws-sdk/client-s3 @aws-sdk/s3-presigned-post

import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3"
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"

const s3 = new S3Client({
  endpoint: "https://storage.yourdomain.com",   // MinIO endpoint
  region: "us-east-1",                           // Required by SDK (any value works with MinIO)
  credentials: {
    accessKeyId: "app-user",
    secretAccessKey: "StrongAppUserPass!"
  },
  forcePathStyle: true,    // Required for MinIO — uses path-style URLs
})

// Upload a file
await s3.send(new PutObjectCommand({
  Bucket: "app-uploads",
  Key: `users/${userId}/avatar.jpg`,
  Body: fileBuffer,
  ContentType: "image/jpeg",
  ACL: "private"
}))

// Generate presigned URL for direct upload (client-side, bypasses your server)
const presignedUrl = await getSignedUrl(s3, new PutObjectCommand({
  Bucket: "app-uploads",
  Key: `uploads/${Date.now()}-${filename}`,
}), { expiresIn: 3600 })  // URL valid for 1 hour

// Generate presigned URL for download (private objects)
const downloadUrl = await getSignedUrl(s3, new GetObjectCommand({
  Bucket: "app-uploads",
  Key: `users/${userId}/document.pdf`,
}), { expiresIn: 300 })  // 5 minutes

Python (boto3)

<code"># pip install boto3 --break-system-packages

import boto3
from botocore.client import Config

s3 = boto3.client(
    's3',
    endpoint_url='https://storage.yourdomain.com',
    aws_access_key_id='app-user',
    aws_secret_access_key='StrongAppUserPass!',
    config=Config(signature_version='s3v4'),
    region_name='us-east-1'
)

# Upload
s3.upload_file('local_file.pdf', 'app-uploads', 'remote/path/file.pdf')

# Download
s3.download_file('app-uploads', 'remote/path/file.pdf', 'local_copy.pdf')

# List objects
response = s3.list_objects_v2(Bucket='app-uploads', Prefix='users/')
for obj in response.get('Contents', []):
    print(obj['Key'], obj['Size'])

Step 5: Integrate with Applications

Laravel (Filesystem)

<code"># config/filesystems.php — add MinIO disk
's3' => [
    'driver' => 's3',
    'key' => env('MINIO_ACCESS_KEY', 'app-user'),
    'secret' => env('MINIO_SECRET_KEY', 'StrongAppUserPass!'),
    'region' => 'us-east-1',
    'bucket' => env('MINIO_BUCKET', 'app-uploads'),
    'url' => env('MINIO_URL', 'https://storage.yourdomain.com'),
    'endpoint' => env('MINIO_ENDPOINT', 'https://storage.yourdomain.com'),
    'use_path_style_endpoint' => true,
],

# In controller:
Storage::disk('s3')->put('users/avatar.jpg', $file);
$url = Storage::disk('s3')->temporaryUrl('users/avatar.jpg', now()->addMinutes(30));

Django (django-storages)

<code"># pip install django-storages boto3
# settings.py:
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_ACCESS_KEY_ID = 'app-user'
AWS_SECRET_ACCESS_KEY = 'StrongAppUserPass!'
AWS_S3_ENDPOINT_URL = 'https://storage.yourdomain.com'
AWS_STORAGE_BUCKET_NAME = 'app-uploads'
AWS_S3_REGION_NAME = 'us-east-1'
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = 'private'

Step 6: Automated Backup to MinIO

<code"># Backup PostgreSQL to MinIO daily
cat > /opt/backup-to-minio.sh << 'EOF' #!/bin/bash DATE=$(date +%Y%m%d_%H%M%S) # Dump PostgreSQL pg_dump -U postgres myapp_production | \ gzip > /tmp/pg_backup_${DATE}.sql.gz

# Upload to MinIO
/usr/local/bin/mc cp /tmp/pg_backup_${DATE}.sql.gz \
  hkminio/backups/postgres/pg_${DATE}.sql.gz

# Keep only last 30 days in MinIO
/usr/local/bin/mc rm --recursive --force \
  --older-than 30d hkminio/backups/postgres/

rm /tmp/pg_backup_${DATE}.sql.gz
echo "Backup complete: $DATE"
EOF
chmod +x /opt/backup-to-minio.sh
crontab -l | { cat; echo "0 3 * * * /opt/backup-to-minio.sh"; } | crontab -

Cost Comparison: MinIO on VPS vs AWS S3

Cost FactorAWS S3 (Asia Pacific)MinIO on HK VPS
Storage (100 GB)~$2.30/monthDisk cost only (~$0.05/GB)
Egress (100 GB to internet)~$8.50/monthIncluded in VPS bandwidth
API requests (1M)~$0.40$0
China latency200–400ms30–60ms (CN2 GIA)
Data jurisdictionAWS US-East (default)Hong Kong (your control)

Conclusion

MinIO on a Hong Kong VPS is a drop-in S3 replacement that eliminates AWS egress fees, keeps data in Hong Kong’s jurisdiction, and serves object requests to mainland Chinese users at 30–60ms rather than 200–400ms from AWS S3. The S3-compatible API means zero application code changes — swap the endpoint URL and credentials. Automated PostgreSQL backups to a private MinIO bucket replace the need for any external backup service.

Host your own S3: Browse Server.HK Hong Kong VPS plans — add extra NVMe storage for large object repositories; MinIO itself uses minimal RAM alongside your application workload.

Recent Posts

  • Monorepo Deployment on Hong Kong VPS: Turborepo and pnpm (2026)
  • GitLab Runner on Hong Kong VPS: Self-Hosted CI/CD Pipeline (2026)
  • Deploy Spring Boot on Hong Kong VPS: Java Microservices for Asia (2026)
  • TimescaleDB on Hong Kong VPS: Time-Series Data for Asia-Pacific (2026)
  • Hong Kong VPS China Accessibility Checklist: Make Your Site Work (2026)

Recent Comments

  1. Hong Kong VPS Uptime and SLA: What 99.9% Uptime Really Means for Your Business (2026) - Server.HK on How to Monitor Your Hong Kong VPS: Uptime, Performance, and Alert Setup Guide (2026)
  2. Best Hong Kong VPS Providers in 2026: Compared by Speed, Routing, and Value - Server.HK on How to Migrate Your Website to a Hong Kong VPS: Zero-Downtime Transfer Guide (2026)
  3. vibramycin injection on How to Choose the Right Hong Kong VPS Plan: A Buyer’s Guide for 2026
  4. allopurinol for gout on CN2 GIA vs BGP vs CN2 GT: What’s the Real Difference for China Connectivity?
  5. antibiotics online purchase on How to Set Up a WordPress Site on a Hong Kong VPS with aaPanel (Step-by-Step 2026)

Knowledge Base

Access detailed guides, tutorials, and resources.

Live Chat

Get instant help 24/7 from our support team.

Send Ticket

Our team typically responds within 10 minutes.

logo
Alipay Cc-paypal Cc-stripe Cc-visa Cc-mastercard Bitcoin
Cloud VPS
  • Hong Kong VPS
  • US VPS
Dedicated Servers
  • Hong Kong Servers
  • US Servers
  • Singapore Servers
  • Japan Servers
More
  • Contact Us
  • Blog
  • Legal
© 2026 Server.HK | Hosting Limited, Hong Kong | Company Registration No. 77008912
Telegram
Telegram @ServerHKBot