* feat(infra): add HCP Terraform for the prod file share (PLAT-77) The prod host will live on a subnet in the syslog VPC. The data volume stays unmanaged and is attached only after a snapshot copy. * fix(infra): pin FileBrowser version to a release tag (PLAT-77) The version is interpolated into the boot script. Reject anything that is not a vX.Y.Z tag. * fix(infra): keep the file share off the public internet (PLAT-77) The instance has no public IP. Office routes use the syslog VPN gateway and other egress uses a NAT gateway. DLM targets the tagged data volume, and replacement detaches stop the instance first.
6.5 KiB
file-share
Personal file share server on AWS — Samba for macOS Finder integration and FileBrowser for web-based file management. Accessible exclusively over the site-to-site VPN.
Infrastructure
The live share is still the management-account CDK stack until cutover proof. The prod replacement is HCP Terraform in terraform/, workspace file-share-prod, trigger terraform/**. CDK deploy on push to main is frozen.
| Path | Role |
|---|---|
terraform/ |
Prod EC2, subnet in the syslog VPC, DLM, and HCP roles |
lib/file-share-stack.ts |
Management-account CDK stack, still the live path until decommission |
bin/app.ts # CDK app entry point — instantiates the stack
lib/file-share-stack.ts # FileShareStack — all resource definitions
cdk.json # App command + CDK feature flags / context
cdk.context.json # Cached VPC/subnet lookups and the resolved AL2023 AMI
cdk.json is the CDK app manifest. Its app command (npx tsx bin/app.ts) runs the TypeScript entry point directly via tsx — no separate compile step is needed for synth or deploy. bin/app.ts instantiates FileShareStack with an explicit stackName: "file-share" (kebab-case, per convention) and the target account/region.
aws-cdk-lib is pinned to an exact version (2.261.0); the aws-cdk CLI is available as a dev dependency and via npx cdk.
Common commands (also exposed as npm scripts):
| Command | Purpose |
|---|---|
npx cdk synth (npm run synth) |
Synthesize the CloudFormation template to cdk.out/ |
npx cdk diff (npm run diff) |
Diff the synthesized stack against what is deployed |
npx cdk deploy (npm run deploy) |
Deploy the stack |
npm run build |
Type-check via tsc |
Architecture
- EC2 —
t4g.small(ARM64, Amazon Linux 2023) in the private subnet. The AMI is cached in the committedcdk.context.json(cachedInContext: true), so deploys never pick up a new AL2023 release implicitly — an AMI change forces instance replacement and must be deliberate (cdk context --reset <ami key> && cdk synth). - Samba — SMB file share at
/data/share, optimized for macOS (vfs_fruit) - FileBrowser — Web UI on port 8080, backed by the same
/data/sharedirectory - SFTP — password auth for user
adam(ForceCommand internal-sftp, same password as SMB); used by Hazel for automated uploads - EBS data volume —
vol-04d951cccacc435b5, 500 GiB gp3 encrypted, mounted at/data. Unmanaged import: the stack references it by ID (Volume.fromVolumeAttributes+CfnVolumeAttachment), so CloudFormation can attach it but can never create, replace, or delete it — the data survives instance replacement and even stack deletion. UserData waits for the attachment, then mounts the existing filesystem; ablkidguard ensures a disk that already has a filesystem is never formatted. - DLM — Daily EBS snapshots at 06:00 UTC, 30-day retention (targets the
file-share-backup=truetag, set directly on the volume) - SSM — Session Manager for instance access (no SSH key)
History: the data volume was originally an inline
blockDevice, which destroyed data on instance replacement (2026-05-27 incident), then a stack-managed standalone volume, which was orphaned when an uncommitted deploy got reverted by CD (2026-06-05 incident). The unmanaged-import design ends that failure class.
Documentation
The canonical map of Sea Haven's AWS infrastructure lives in Confluence. This project's file-share stack is represented there as a Mermaid subgraph.
- AWS Architecture Map (Confluence, IT space, page 1540098)
Access
Requires VPN connection to the office network (10.10.0.0/16).
Finder (SMB)
- Finder > Go > Connect to Server
- Enter
smb://<private-ip>/files - Authenticate with
adamand the password fromfile-share/smb-passwordin Secrets Manager
FileBrowser (Web)
Open http://<private-ip>:8080 in a browser.
Secrets
Both stored in AWS Secrets Manager:
| Secret | Purpose |
|---|---|
file-share/smb-password |
Samba user password |
file-share/filebrowser-password |
FileBrowser admin password |
Create these secrets before deploying the stack:
aws secretsmanager create-secret --name file-share/smb-password --secret-string '<password>'
aws secretsmanager create-secret --name file-share/filebrowser-password --secret-string '<password>'
Deploy
Prod changes go through HCP Terraform workspace file-share-prod (manual apply until the move is sealed). The bootstrap apply creates the HCP roles and the instance boundary. The following apply, using hcptf-file-share, creates the subnet, security group, and DLM policy. data_volume_id stays empty until the snapshot copy exists, so those applies do not boot an instance.
The management-account CDK workflow no longer runs on push. workflow_dispatch remains for an explicit rollback of that stack.
The instance has no public IP. Its route table sends 10.10.0.0/16 and 10.30.0.0/16 through the syslog VPN gateway and everything else through a NAT gateway in the syslog public subnet. 10.10.0.0/16 is the Ronkonkoma office LAN and 10.30.0.0/16 is the Locust office LAN, the same pair the syslog VPN already routes. 10.20.0.0/16 is the management VPC and is not routed here.
Clients use the private IP. Office routing must include 10.40.20.0/24 on the existing syslog IPsec before SMB from the office will work. A check from 10.10.70.0/24 on 2026-09-28 reached the gateway for 10.40.10.254 and got no hop-1 reply for 10.40.20.1. The nightly DLM policy targets volumes tagged file-share-backup=true. Tag the copied volume with that key at cutover.
Expanding Storage
The data volume is not managed by CloudFormation (imported by ID), so changing a size in lib/file-share-stack.ts has no effect. Expand it directly — no downtime:
aws ec2 modify-volume --volume-id vol-04d951cccacc435b5 --size <new-GiB>- Wait for the modification to leave
modifying:aws ec2 describe-volumes-modifications --volume-ids vol-04d951cccacc435b5 - Resize the filesystem via an SSM session:
sudo resize2fs /dev/nvme1n1 # xvdf surfaces as nvme1n1 on Nitro instances