600 lines
27 KiB
HTML
600 lines
27 KiB
HTML
{% extends "base.html" %}
|
|
{% block content %}
|
|
<section class="docs-hero p-4 p-md-5 rounded-4 mb-4">
|
|
<div class="d-flex flex-column flex-lg-row justify-content-between gap-3">
|
|
<div>
|
|
<p class="text-uppercase fw-semibold small text-white-50 mb-2">Documentation</p>
|
|
<h1 class="display-6 fw-semibold mb-2">Your guide to MyFSIO</h1>
|
|
<p class="lead mb-0 text-light">Follow these steps to install, authenticate, master the console, and automate everything through the API.</p>
|
|
</div>
|
|
<div class="docs-callout text-light">
|
|
<div class="small text-uppercase opacity-75">API base URL</div>
|
|
<code class="fs-6 text-wrap">{{ api_base }}</code>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<div class="row g-4">
|
|
<div class="col-xl-8">
|
|
<article id="setup" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">01</span>
|
|
<h2 class="h4 mb-0">Set up & run locally</h2>
|
|
</div>
|
|
<p class="text-muted">Prepare a virtual environment, install dependencies, and launch both servers for a complete console + API experience.</p>
|
|
<ol class="docs-steps">
|
|
<li>Install Python 3.11+ plus system build tools.</li>
|
|
<li>Create a virtual environment and install <code>requirements.txt</code>.</li>
|
|
<li>Start the services with <code>python run.py</code>.</li>
|
|
</ol>
|
|
<pre class="mb-3"><code class="language-bash">python -m venv .venv
|
|
. .venv/Scripts/activate # PowerShell: .\\.venv\\Scripts\\Activate.ps1
|
|
pip install -r requirements.txt
|
|
|
|
# Run both API and UI (Development)
|
|
python run.py
|
|
|
|
# Run in Production (Waitress server)
|
|
python run.py --prod
|
|
|
|
# Or run individually
|
|
python run.py --mode api
|
|
python run.py --mode ui
|
|
</code></pre>
|
|
<h3 class="h6 mt-4 mb-2">Configuration</h3>
|
|
<p class="text-muted small">Configuration defaults live in <code>app/config.py</code>. You can override them using environment variables. This is critical for production deployments behind proxies.</p>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm table-bordered small mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Variable</th>
|
|
<th>Default</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>API_BASE_URL</code></td>
|
|
<td><code>http://127.0.0.1:5000</code></td>
|
|
<td>The public URL of the API. <strong>Required</strong> if running behind a proxy or if the UI and API are on different domains. Ensures presigned URLs are generated correctly.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>STORAGE_ROOT</code></td>
|
|
<td><code>./data</code></td>
|
|
<td>Directory for buckets and objects.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>MAX_UPLOAD_SIZE</code></td>
|
|
<td><code>5 GB</code></td>
|
|
<td>Max request body size.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>SECRET_KEY</code></td>
|
|
<td>(Random)</td>
|
|
<td>Flask session key. Set this in production.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>APP_HOST</code></td>
|
|
<td><code>0.0.0.0</code></td>
|
|
<td>Bind interface.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>APP_PORT</code></td>
|
|
<td><code>5000</code></td>
|
|
<td>Listen port.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>ENCRYPTION_ENABLED</code></td>
|
|
<td><code>false</code></td>
|
|
<td>Enable server-side encryption support.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>KMS_ENABLED</code></td>
|
|
<td><code>false</code></td>
|
|
<td>Enable KMS key management for encryption.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
<article id="background" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">02</span>
|
|
<h2 class="h4 mb-0">Running in background</h2>
|
|
</div>
|
|
<p class="text-muted">For production or server deployments, run MyFSIO as a background service so it persists after you close the terminal.</p>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">Quick Start (nohup)</h3>
|
|
<p class="text-muted small">Simplest way to run in background—survives terminal close:</p>
|
|
<pre class="mb-3"><code class="language-bash"># Using Python
|
|
nohup python run.py --prod > /dev/null 2>&1 &
|
|
|
|
# Using compiled binary
|
|
nohup ./myfsio > /dev/null 2>&1 &
|
|
|
|
# Check if running
|
|
ps aux | grep myfsio</code></pre>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">Screen / Tmux</h3>
|
|
<p class="text-muted small">Attach/detach from a persistent session:</p>
|
|
<pre class="mb-3"><code class="language-bash"># Start in a detached screen session
|
|
screen -dmS myfsio ./myfsio
|
|
|
|
# Attach to view logs
|
|
screen -r myfsio
|
|
|
|
# Detach: press Ctrl+A, then D</code></pre>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">Systemd (Recommended for Production)</h3>
|
|
<p class="text-muted small">Create <code>/etc/systemd/system/myfsio.service</code>:</p>
|
|
<pre class="mb-3"><code class="language-ini">[Unit]
|
|
Description=MyFSIO S3-Compatible Storage
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=myfsio
|
|
WorkingDirectory=/opt/myfsio
|
|
ExecStart=/opt/myfsio/myfsio
|
|
Restart=on-failure
|
|
RestartSec=5
|
|
Environment=MYFSIO_DATA_DIR=/var/lib/myfsio
|
|
Environment=API_BASE_URL=https://s3.example.com
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target</code></pre>
|
|
<p class="text-muted small">Then enable and start:</p>
|
|
<pre class="mb-0"><code class="language-bash">sudo systemctl daemon-reload
|
|
sudo systemctl enable myfsio
|
|
sudo systemctl start myfsio
|
|
|
|
# Check status
|
|
sudo systemctl status myfsio
|
|
sudo journalctl -u myfsio -f # View logs</code></pre>
|
|
</div>
|
|
</article>
|
|
<article id="auth" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">03</span>
|
|
<h2 class="h4 mb-0">Authenticate & manage IAM</h2>
|
|
</div>
|
|
<p class="text-muted">MyFSIO seeds <code>data/.myfsio.sys/config/iam.json</code> with <code>localadmin/localadmin</code>. Sign in once, rotate it, then grant least-privilege access to teammates and tools.</p>
|
|
<div class="docs-highlight mb-3">
|
|
<ol class="mb-0">
|
|
<li>Visit <code>/ui/login</code>, enter the bootstrap credentials, and rotate them immediately from the IAM page.</li>
|
|
<li>Create additional users with descriptive display names and AWS-style inline policies (for example <code>{"bucket": "*", "actions": ["list", "read"]}</code>).</li>
|
|
<li>Rotate secrets when sharing with CI jobs—new secrets display once and persist to <code>data/.myfsio.sys/config/iam.json</code>.</li>
|
|
<li>Bucket policies layer on top of IAM. Apply Private/Public presets or paste custom JSON; changes reload instantly.</li>
|
|
</ol>
|
|
</div>
|
|
<p class="mb-0 text-muted">All API calls require <code>X-Access-Key</code> and <code>X-Secret-Key</code> headers. The UI stores them in the Flask session after you log in.</p>
|
|
</div>
|
|
</article>
|
|
<article id="console" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">04</span>
|
|
<h2 class="h4 mb-0">Use the console effectively</h2>
|
|
</div>
|
|
<p class="text-muted">Each workspace models an S3 workflow so you can administer buckets end-to-end.</p>
|
|
<div class="docs-pill-list">
|
|
<div>
|
|
<h3 class="h6 text-uppercase text-muted">Buckets</h3>
|
|
<ul>
|
|
<li>Create/delete buckets from the overview. Badges reveal IAM-only, public-read, or custom-policy states.</li>
|
|
<li>Summary stats show live object counts and total capacity; click through for inventories.</li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h3 class="h6 text-uppercase text-muted">Uploads</h3>
|
|
<ul>
|
|
<li>Drag and drop folders or files into the upload modal. Objects above 16 MB switch to multipart automatically.</li>
|
|
<li>Progress rows highlight retries, throughput, and completion even if you close the modal.</li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h3 class="h6 text-uppercase text-muted">Object details</h3>
|
|
<ul>
|
|
<li>Selecting an object opens the preview card with metadata, inline viewers, presign generator, and version history.</li>
|
|
<li>Trigger downloads, deletes, restores, or metadata refreshes without leaving the panel.</li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h3 class="h6 text-uppercase text-muted">Policies & versioning</h3>
|
|
<ul>
|
|
<li>Toggle versioning (requires write access). Archived-only keys are flagged so you can restore them quickly.</li>
|
|
<li>The policy editor saves drafts, ships with presets, and hot-reloads <code>data/.myfsio.sys/config/bucket_policies.json</code>.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
<article id="automation" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">05</span>
|
|
<h2 class="h4 mb-0">Automate with CLI & tools</h2>
|
|
</div>
|
|
<p class="text-muted">Point standard S3 clients at {{ api_base }} and reuse the same IAM credentials.</p>
|
|
<div class="mb-4">
|
|
<h3 class="h6 text-uppercase text-muted">AWS CLI</h3>
|
|
<pre class="mb-3"><code class="language-bash">aws configure set aws_access_key_id <access_key>
|
|
aws configure set aws_secret_access_key <secret_key>
|
|
aws configure set default.region us-east-1
|
|
|
|
aws --endpoint-url {{ api_base }} s3 ls
|
|
aws --endpoint-url {{ api_base }} s3api create-bucket --bucket demo
|
|
aws --endpoint-url {{ api_base }} s3 cp ./sample.txt s3://demo/sample.txt
|
|
</code></pre>
|
|
</div>
|
|
<div class="mb-4">
|
|
<h3 class="h6 text-uppercase text-muted">s3cmd</h3>
|
|
<pre class="mb-3"><code class="language-bash">cat > ~/.s3cfg-myfsio <<'EOF'
|
|
host_base = {{ api_host }}
|
|
host_bucket = %(bucket)s.{{ api_host }}
|
|
access_key = <access_key>
|
|
secret_key = <secret_key>
|
|
use_https = False
|
|
signature_v2 = False
|
|
EOF
|
|
|
|
s3cmd --config ~/.s3cfg-myfsio ls
|
|
s3cmd --config ~/.s3cfg-myfsio put notes.txt s3://demo/notes.txt
|
|
</code></pre>
|
|
</div>
|
|
<div>
|
|
<h3 class="h6 text-uppercase text-muted">curl / HTTPie</h3>
|
|
<pre class="mb-0"><code class="language-bash">curl {{ api_base }}/ \
|
|
-H "X-Access-Key: <access_key>" \
|
|
-H "X-Secret-Key: <secret_key>"
|
|
|
|
curl -X PUT {{ api_base }}/demo/notes.txt \
|
|
-H "X-Access-Key: <access_key>" \
|
|
-H "X-Secret-Key: <secret_key>" \
|
|
--data-binary @notes.txt
|
|
|
|
curl -X POST {{ api_base }}/presign/demo/notes.txt \
|
|
-H "Content-Type: application/json" \
|
|
-H "X-Access-Key: <access_key>" \
|
|
-H "X-Secret-Key: <secret_key>" \
|
|
-d '{"method":"GET", "expires_in": 900}'
|
|
</code></pre>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
<article id="api" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">06</span>
|
|
<h2 class="h4 mb-0">Key REST endpoints</h2>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm table-borderless align-middle docs-table mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">Method</th>
|
|
<th scope="col">Path</th>
|
|
<th scope="col">Purpose</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>GET</td>
|
|
<td><code>/</code></td>
|
|
<td>List buckets accessible to the caller.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>PUT</td>
|
|
<td><code>/<bucket></code></td>
|
|
<td>Create a bucket.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>DELETE</td>
|
|
<td><code>/<bucket></code></td>
|
|
<td>Delete a bucket (must be empty).</td>
|
|
</tr>
|
|
<tr>
|
|
<td>GET</td>
|
|
<td><code>/<bucket></code></td>
|
|
<td>List objects (supports <code>prefix</code> / <code>max-keys</code> queries).</td>
|
|
</tr>
|
|
<tr>
|
|
<td>PUT</td>
|
|
<td><code>/<bucket>/<key></code></td>
|
|
<td>Upload or overwrite an object; UI helper handles multipart flows.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>GET</td>
|
|
<td><code>/<bucket>/<key></code></td>
|
|
<td>Download an object (UI adds <code>?download=1</code> to force attachment).</td>
|
|
</tr>
|
|
<tr>
|
|
<td>DELETE</td>
|
|
<td><code>/<bucket>/<key></code></td>
|
|
<td>Delete an object.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>GET/PUT/DELETE</td>
|
|
<td><code>/bucket-policy/<bucket></code></td>
|
|
<td>Fetch, upsert, or remove a bucket policy.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>POST</td>
|
|
<td><code>/presign/<bucket>/<key></code></td>
|
|
<td>Generate SigV4 URLs for GET/PUT/DELETE with custom expiry.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<p class="small text-muted mt-3 mb-0">All responses include <code>X-Request-Id</code> for tracing. Logs land in <code>logs/api.log</code> and <code>logs/ui.log</code>.</p>
|
|
</div>
|
|
</article>
|
|
<article id="examples" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">07</span>
|
|
<h2 class="h4 mb-0">API Examples</h2>
|
|
</div>
|
|
<p class="text-muted">Common operations using boto3.</p>
|
|
|
|
<h5 class="mt-4">Multipart Upload</h5>
|
|
<pre><code class="language-python">import boto3
|
|
|
|
s3 = boto3.client('s3', endpoint_url='{{ api_base }}')
|
|
|
|
# Initiate
|
|
response = s3.create_multipart_upload(Bucket='mybucket', Key='large.bin')
|
|
upload_id = response['UploadId']
|
|
|
|
# Upload parts
|
|
parts = []
|
|
chunks = [b'chunk1', b'chunk2'] # Example data chunks
|
|
for part_number, chunk in enumerate(chunks, start=1):
|
|
response = s3.upload_part(
|
|
Bucket='mybucket',
|
|
Key='large.bin',
|
|
PartNumber=part_number,
|
|
UploadId=upload_id,
|
|
Body=chunk
|
|
)
|
|
parts.append({'PartNumber': part_number, 'ETag': response['ETag']})
|
|
|
|
# Complete
|
|
s3.complete_multipart_upload(
|
|
Bucket='mybucket',
|
|
Key='large.bin',
|
|
UploadId=upload_id,
|
|
MultipartUpload={'Parts': parts}
|
|
)</code></pre>
|
|
</div>
|
|
</article>
|
|
<article id="replication" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">08</span>
|
|
<h2 class="h4 mb-0">Site Replication</h2>
|
|
</div>
|
|
<p class="text-muted">Automatically copy new objects to another MyFSIO instance or S3-compatible service for backup or disaster recovery.</p>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">Setup Guide</h3>
|
|
<ol class="docs-steps mb-3">
|
|
<li>
|
|
<strong>Prepare Target:</strong> On the destination server, create a bucket (e.g., <code>backup-bucket</code>) and an IAM user with write permissions.
|
|
</li>
|
|
<li>
|
|
<strong>Connect Source:</strong> On this server, go to <a href="{{ url_for('ui.connections_dashboard') }}">Connections</a> and add the target's API URL and credentials.
|
|
</li>
|
|
<li>
|
|
<strong>Enable Rule:</strong> Go to the source bucket's <strong>Replication</strong> tab, select the connection, and enter the target bucket name.
|
|
</li>
|
|
</ol>
|
|
|
|
<div class="alert alert-light border mb-0">
|
|
<div class="d-flex gap-2">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-terminal text-muted mt-1" viewBox="0 0 16 16">
|
|
<path d="M6 9a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3A.5.5 0 0 1 6 9zM3.854 4.146a.5.5 0 1 0-.708.708L4.793 6.5 3.146 8.146a.5.5 0 1 0 .708.708l2-2a.5.5 0 0 0 0-.708l-2-2z"/>
|
|
<path d="M2 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H2zm12 1a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h12z"/>
|
|
</svg>
|
|
<div>
|
|
<strong>Headless Target Setup?</strong>
|
|
<p class="small text-muted mb-0">If your target server has no UI, use the Python API directly to bootstrap credentials. See <code>docs.md</code> in the project root for the <code>setup_target.py</code> script.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">Bidirectional Replication (Active-Active)</h3>
|
|
<p class="small text-muted">To set up two-way replication (Server A ↔ Server B):</p>
|
|
<ol class="docs-steps mb-3">
|
|
<li>Follow the steps above to replicate <strong>A → B</strong>.</li>
|
|
<li>Repeat the process on Server B to replicate <strong>B → A</strong> (create a connection to A, enable rule).</li>
|
|
</ol>
|
|
<p class="small text-muted mb-0">
|
|
<strong>Loop Prevention:</strong> The system automatically detects replication traffic using a custom User-Agent (<code>S3ReplicationAgent</code>). This prevents infinite loops where an object replicated from A to B is immediately replicated back to A.
|
|
<br>
|
|
<strong>Deletes:</strong> Deleting an object on one server will propagate the deletion to the other server.
|
|
</p>
|
|
</div>
|
|
</article>
|
|
<article id="encryption" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">09</span>
|
|
<h2 class="h4 mb-0">Encryption</h2>
|
|
</div>
|
|
<p class="text-muted">Protect data at rest with server-side encryption using AES-256-GCM. Objects are encrypted before being written to disk and decrypted transparently on read.</p>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">Encryption Types</h3>
|
|
<div class="table-responsive mb-3">
|
|
<table class="table table-sm table-bordered small">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>AES-256 (SSE-S3)</strong></td>
|
|
<td>Server-managed encryption using a local master key</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>KMS (SSE-KMS)</strong></td>
|
|
<td>Encryption using customer-managed keys via the built-in KMS</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">Enabling Encryption</h3>
|
|
<ol class="docs-steps mb-3">
|
|
<li>
|
|
<strong>Set environment variables:</strong>
|
|
<pre class="mb-2"><code class="language-bash"># PowerShell
|
|
$env:ENCRYPTION_ENABLED = "true"
|
|
$env:KMS_ENABLED = "true" # Optional
|
|
python run.py
|
|
|
|
# Bash
|
|
export ENCRYPTION_ENABLED=true
|
|
export KMS_ENABLED=true
|
|
python run.py</code></pre>
|
|
</li>
|
|
<li>
|
|
<strong>Configure bucket encryption:</strong> Navigate to your bucket → <strong>Properties</strong> tab → <strong>Default Encryption</strong> card → Click <strong>Enable Encryption</strong>.
|
|
</li>
|
|
<li>
|
|
<strong>Choose algorithm:</strong> Select <strong>AES-256</strong> for server-managed keys or <strong>aws:kms</strong> to use a KMS-managed key.
|
|
</li>
|
|
</ol>
|
|
|
|
<div class="alert alert-warning border-warning bg-warning-subtle mb-3">
|
|
<div class="d-flex gap-2">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-exclamation-triangle mt-1" viewBox="0 0 16 16">
|
|
<path d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z"/>
|
|
<path d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z"/>
|
|
</svg>
|
|
<div>
|
|
<strong>Important:</strong> Only <em>new uploads</em> after enabling encryption will be encrypted. Existing objects remain unencrypted.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">KMS Key Management</h3>
|
|
<p class="small text-muted">When <code>KMS_ENABLED=true</code>, manage encryption keys via the API:</p>
|
|
<pre class="mb-3"><code class="language-bash"># Create a new KMS key
|
|
curl -X POST {{ api_base }}/kms/keys \
|
|
-H "Content-Type: application/json" \
|
|
-H "X-Access-Key: <key>" -H "X-Secret-Key: <secret>" \
|
|
-d '{"alias": "my-key", "description": "Production key"}'
|
|
|
|
# List all keys
|
|
curl {{ api_base }}/kms/keys \
|
|
-H "X-Access-Key: <key>" -H "X-Secret-Key: <secret>"
|
|
|
|
# Rotate a key (creates new key material)
|
|
curl -X POST {{ api_base }}/kms/keys/{key-id}/rotate \
|
|
-H "X-Access-Key: <key>" -H "X-Secret-Key: <secret>"
|
|
|
|
# Disable/Enable a key
|
|
curl -X POST {{ api_base }}/kms/keys/{key-id}/disable \
|
|
-H "X-Access-Key: <key>" -H "X-Secret-Key: <secret>"
|
|
|
|
# Schedule key deletion (30-day waiting period)
|
|
curl -X DELETE "{{ api_base }}/kms/keys/{key-id}?waiting_period_days=30" \
|
|
-H "X-Access-Key: <key>" -H "X-Secret-Key: <secret>"</code></pre>
|
|
|
|
<h3 class="h6 text-uppercase text-muted mt-4">How It Works</h3>
|
|
<p class="small text-muted mb-0">
|
|
<strong>Envelope Encryption:</strong> Each object is encrypted with a unique Data Encryption Key (DEK). The DEK is then encrypted (wrapped) by the master key or KMS key and stored alongside the ciphertext. On read, the DEK is unwrapped and used to decrypt the object transparently.
|
|
</p>
|
|
</div>
|
|
</article>
|
|
<article id="troubleshooting" class="card shadow-sm docs-section">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
<span class="docs-section-kicker">10</span>
|
|
<h2 class="h4 mb-0">Troubleshooting & tips</h2>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm align-middle docs-table mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">Symptom</th>
|
|
<th scope="col">Likely cause</th>
|
|
<th scope="col">Fix</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>403 from API despite Public preset</td>
|
|
<td>Policy not saved or ARN mismatch</td>
|
|
<td>Reapply the preset and confirm <code>arn:aws:s3:::bucket/*</code> matches the bucket name.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>UI shows stale policy/object data</td>
|
|
<td>Browser cached prior state</td>
|
|
<td>Refresh; the server hot-reloads <code>data/.myfsio.sys/config/bucket_policies.json</code> and storage metadata.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Presign dialog returns 403</td>
|
|
<td>User lacks required <code>read/write/delete</code> action or bucket policy denies</td>
|
|
<td>Update IAM inline policies or remove conflicting deny statements.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Large uploads fail instantly</td>
|
|
<td><code>MAX_UPLOAD_SIZE</code> exceeded</td>
|
|
<td>Raise the env var or split the object.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Requests hit the wrong host</td>
|
|
<td>Proxy headers missing or <code>API_BASE_URL</code> incorrect</td>
|
|
<td>Ensure your proxy sends <code>X-Forwarded-Host</code>/<code>Proto</code> headers, or explicitly set <code>API_BASE_URL</code> to your public domain.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
<div class="col-xl-4">
|
|
<aside class="card shadow-sm docs-sidebar">
|
|
<div class="card-body">
|
|
<h3 class="h6 text-uppercase text-muted mb-3">On this page</h3>
|
|
<ul class="list-unstyled docs-toc mb-4">
|
|
<li><a href="#setup">Set up & run</a></li>
|
|
<li><a href="#background">Running in background</a></li>
|
|
<li><a href="#auth">Authentication & IAM</a></li>
|
|
<li><a href="#console">Console tour</a></li>
|
|
<li><a href="#automation">Automation / CLI</a></li>
|
|
<li><a href="#api">REST endpoints</a></li>
|
|
<li><a href="#examples">API Examples</a></li>
|
|
<li><a href="#replication">Site Replication</a></li>
|
|
<li><a href="#encryption">Encryption</a></li>
|
|
<li><a href="#troubleshooting">Troubleshooting</a></li>
|
|
</ul>
|
|
<div class="docs-sidebar-callouts">
|
|
<div>
|
|
<div class="small text-uppercase text-muted">API base</div>
|
|
<code class="d-block">{{ api_base }}</code>
|
|
</div>
|
|
<div>
|
|
<div class="small text-uppercase text-muted">Sample user</div>
|
|
<code class="d-block">localadmin / localadmin</code>
|
|
</div>
|
|
<div>
|
|
<div class="small text-uppercase text-muted">Logs</div>
|
|
<span class="text-muted small">logs/api.log · logs/ui.log</span>
|
|
</div>
|
|
</div>
|
|
<div class="mt-4">
|
|
<p class="small text-muted mb-1">Need more automation? Extend <code>app/s3_api.py</code> or wrap <code>run_api.py</code> with gunicorn for production-style deployments.</p>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|