Skip to main content
HostwaresHostwares

Security

Harden your Hostwares workloads — TLS, headers, secrets, network isolation, and compliance best practices.

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.

LayerDefaultYour Responsibility
Transport (TLS)Auto-provisioned & renewedEnforce HTTPS in app & set HSTS
SecretsEncrypted at rest (AES-256)Rotate keys, scope per environment
NetworkPer-project isolationRestrict DB to private network
BuildEphemeral, non-privilegedPin dependencies, enable SBOM
AccessTeam RBACLeast-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; preload

Only 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.

HeaderRecommended ValuePurpose
Content-Security-Policydefault-src 'self' + allowlistMitigates XSS & data injection
X-Frame-OptionsDENY or SAMEORIGINPrevents clickjacking
X-Content-Type-OptionsnosniffBlocks MIME sniffing
Referrer-Policystrict-origin-when-cross-originLimits referrer leakage
Permissions-PolicyDisable unused featuresReduces 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_URL for 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
PracticeDoAvoid
RotationRotate every 90 days; revoke old keys immediatelyReusing the same key across envs for months
ScopePer-site, per-environment keysOne global key for all projects
StorageHostwares encrypted env / vaultHardcoded 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_URL pooled) 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 healthy

Authentication & 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., distroless or alpine).
# 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

AreaHostwares Posture
Encryption at restAES-256-GCM for secrets & DB volumes
Encryption in transitTLS 1.2+ enforced at edge
BackupsEncrypted snapshots; see Backups
LoggingAccess & deploy logs retained per plan
Data residencyChoose 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)