Overview
Hostwares applies defense-in-depth by default — every site gets automatic TLS, isolated runtime networks, encrypted secrets, and hardened build environments. This guide explains what is handled for you and what you should configure in your application.
| Layer | Default | Your Responsibility |
|---|---|---|
| Transport (TLS) | Auto-provisioned & renewed | Enforce HTTPS in app & set HSTS |
| Secrets | Encrypted at rest (AES-256) | Rotate keys, scope per environment |
| Network | Per-project isolation | Restrict DB to private network |
| Build | Ephemeral, non-privileged | Pin dependencies, enable SBOM |
| Access | Team RBAC | Least-privilege roles, 2FA |
TLS & Certificates
All Hostwares-managed domains get TLS via Let's Encrypt. Certificates are issued on domain verification and auto-renewed 30 days before expiry. No manual renewal needed.
- Hostwares subdomains (
*.hostwares.app) — TLS on first deploy, no setup. - Custom domains — TLS issued after DNS verification. See Domains & SSL.
- Bring-your-own certificate — upload via Domains → Advanced → Custom Certificate if you require EV or private CA.
# Force HTTPS at the edge — add to your app's middleware
# Example (framework-agnostic): redirect http -> https
if (req.headers["x-forwarded-proto"] !== "https") {
return Response.redirect("https://" + req.headers.host + req.url, 301);
}Enforcing HSTS
# Recommended header (send only over HTTPS)
Strict-Transport-Security: max-age=63072000; includeSubDomains; preloadOnly enable preload after you are committed to HTTPS on all subdomains.
Security Headers
Set these headers from your application (reverse proxy or framework middleware). Hostwares does not override app-set headers.
| Header | Recommended Value | Purpose |
|---|---|---|
Content-Security-Policy | default-src 'self' + allowlist | Mitigates XSS & data injection |
X-Frame-Options | DENY or SAMEORIGIN | Prevents clickjacking |
X-Content-Type-Options | nosniff | Blocks MIME sniffing |
Referrer-Policy | strict-origin-when-cross-origin | Limits referrer leakage |
Permissions-Policy | Disable unused features | Reduces attack surface |
# Example: Next.js / generic Node (next.config.js or middleware)
async headers() {
return [{
source: "/:path*",
headers: [
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
{ key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains" },
],
}];
}
# Nginx equivalent
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;CSP starter
Content-Security-Policy: default-src 'self';
script-src 'self' https://cdn.hostwares.app;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.hostwares.com;
frame-ancestors 'none'Secrets Management
Environment variables marked as secrets are encrypted at rest with AES-256-GCM and only decrypted inside your container at runtime. They never appear in build logs after masking.
- Set via Site → Environment or
PATCH /api/sites/:id. - Separate values per environment — use
DATABASE_URLfor production only, a different value for previews. - Mark sensitive keys as Encrypted so they are masked in the dashboard.
# Good: scoped per environment via API
curl -X PATCH https://hostwares.com/api/sites/$SITE_ID \
-H "Authorization: Bearer $HOSTWARES_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"envVariables": [
{"key": "DATABASE_URL", "value": "postgres://...", "encrypted": true},
{"key": "JWT_SECRET", "value": "replace-me-32-chars", "encrypted": true}
]
}'
# Bad: never commit secrets
# .env committed to git -> exposed in clone logs| Practice | Do | Avoid |
|---|---|---|
| Rotation | Rotate every 90 days; revoke old keys immediately | Reusing the same key across envs for months |
| Scope | Per-site, per-environment keys | One global key for all projects |
| Storage | Hostwares encrypted env / vault | Hardcoded in repo or Docker image |
Network Isolation
Each project runs in its own network namespace. Containers can reach the internet and their project's databases/services, but not other projects' workloads.
- Databases are private by default — only reachable from containers in the same project. No public port.
- To expose a database externally, explicitly enable Public Access and allowlist IPs.
- Use connection pooling (
pgbouncer/DATABASE_URLpooled) to limit concurrent connections.
# Connect from app container (private network)
DATABASE_URL=postgresql://user:[email protected]:5432/app
# Health check should stay internal
HEALTHCHECK_PATH=/api/health # not exposed to public until app is healthyAuthentication & Access
Secure your team and your app:
- Team RBAC — Owner, Admin, Developer, Viewer. See Teams & Permissions.
- 2FA — enable from Account → Security.
- API keys — prefix
sk_, scoped to your account; delete unused keys. Never log them. - App auth — enforce session handling server-side; do not trust client-set cookies alone.
# Verify webhook signatures (HMAC-SHA256)
import crypto from "crypto";
function verifySignature(rawBody, signature, secret) {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}Supply Chain
Builds run in ephemeral, non-privileged containers that are destroyed after each deploy.
- Pin dependency versions with lockfiles (
package-lock.json/pnpm-lock.yaml/requirements.txt). - Enable Dependabot / Renovate for automated security updates.
- Use private registries with credentials stored as encrypted env vars — not baked into images.
- For Docker, use multi-stage builds and a minimal final image (e.g.,
distrolessoralpine).
# Dockerfile: minimal final stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./
USER node
EXPOSE 3000
CMD ["node", "server.js"]Compliance Notes
| Area | Hostwares Posture |
|---|---|
| Encryption at rest | AES-256-GCM for secrets & DB volumes |
| Encryption in transit | TLS 1.2+ enforced at edge |
| Backups | Encrypted snapshots; see Backups |
| Logging | Access & deploy logs retained per plan |
| Data residency | Choose region at project creation |
For SOC 2, GDPR DPA, or custom compliance questionnaires, contact [email protected].
Security Checklist
- ✅ Custom domain has valid TLS and HSTS enabled
- ✅ Security headers set (CSP, X-Frame-Options, etc.)
- ✅ All secrets marked encrypted and scoped per environment
- ✅ Database not publicly exposed unless required
- ✅ Team uses least-privilege roles + 2FA
- ✅ Dependencies pinned and auto-updated
- ✅ Webhook signatures verified
- ✅ Backups and restore tested (see Backups)