Creating a New Machine#
This guide covers setting up a new machine in the tinsnip infrastructure, including prerequisites, NFS setup, machine configuration, and testing.
Decisions to Make First#
Before starting, you need to decide on these key inputs:
1. Service Name#
Give the thing you are making a name - this might be the product name (lldap or caddy) or a name which wraps a product of your own like gazette or daffodyl.
- Currently configured:
tinsnip,gazette - You can add more in the future
2. Environment#
Decide if this is for production use or testing. This affects which UID and ports get assigned.
prod- Production environment (UID: xxx00)test- Test environment (UID: xxx10)
3. NAS Server#
Provide the hostname or IP address of your NAS where data will be stored.
- Hostname example:
DS412plus,nas.local - IP example:
192.168.1.100
4. Sheet (Optional)#
If you're running services for multiple organizations or want to separate your services from the default, set a custom sheet.
- Default:
dynamicalsystem - Custom: Your organization name (e.g.,
mycompany)
Prerequisites#
Machine Requirements#
- OS: Ubuntu 20.04 or later (tested on 20.04 and 22.04)
- User: Account with sudo privileges
- Network: Access to NAS and internet for Docker installation
- Resources: At least 2GB RAM, 10GB disk space
NAS Requirements#
- Synology NAS with DSM 6.x or later
- SSH access to NAS with administrative privileges
- Available storage for service data
Verify Prerequisites#
# Check Ubuntu version
lsb_release -a
# Check sudo access
sudo -v && echo "✓ sudo access confirmed" || echo "✗ Need sudo access"
# Test NAS connectivity
ping -c 1 your-nas-hostname
Overview#
Creating a new machine involves:
- Sheet Configuration: Set the organizational sheet (defaults to
dynamicalsystem) - NAS Setup: Create NFS exports with proper UID mapping
- Machine Setup: Install and configure the machine environment
- Service Deployment: Deploy services with proper isolation
- Testing: Validate the complete setup
Step 1: Tinsnip Sheet Configuration#
The system supports configurable sheets for multi-tenant deployments. The sheet affects NFS paths and XDG directory organization.
Setting the Sheet#
Option 1: Environment Variable
export TIN_SHEET=mycompany
./machine/setup.sh tinsnip test DS412plus
Option 2: System-wide Configuration
echo "mycompany" | sudo tee /etc/tinsnip-sheet
./machine/setup.sh tinsnip test DS412plus
Default: If no sheet is configured, dynamicalsystem is used.
For detailed sheet configuration options, see SHEET_CONFIGURATION.md.
Step 2: NAS Setup (Critical)#
Create Directory Structure#
On your Synology NAS, create the directory structure for your sheet:
# For topsheet (default sheet, most users deploy here)
/volume1/topsheet/
├── station/
│ ├── prod/ (will be owned by UID 50000)
│ └── test/ (will be owned by UID 50010)
└── gazette/
├── prod/ (will be owned by UID 50100)
└── test/ (will be owned by UID 50110)
# For custom sheet (infrastructure)
/volume1/tinsnip/infrastructure/
├── station/
│ ├── prod/ (will be owned by UID 10000)
│ └── test/ (will be owned by UID 10010)
└── gazette/
├── prod/ (will be owned by UID 11000)
└── test/ (will be owned by UID 11110)
Create directories and set ownership:
# SSH into NAS
ssh admin@synology-ip
# Create directory structure (replace {sheet} with your sheet)
sudo mkdir -p /volume1/{sheet}/{tinsnip,gazette}/{prod,test}
# Set ownership to match service UIDs
sudo chown 11000:11000 /volume1/{sheet}/tinsnip/prod
sudo chown 11010:11010 /volume1/{sheet}/tinsnip/test
sudo chown 11100:11100 /volume1/{sheet}/gazette/prod
sudo chown 11110:11110 /volume1/{sheet}/gazette/test
# Example for custom sheet:
sudo mkdir -p /volume1/mycompany/{tinsnip,gazette}/{prod,test}
sudo chown 11000:11000 /volume1/mycompany/tinsnip/prod
sudo chown 11010:11010 /volume1/mycompany/tinsnip/test
sudo chown 11100:11100 /volume1/mycompany/gazette/prod
sudo chown 11110:11110 /volume1/mycompany/gazette/test
Important: The chown commands ensure the directories are owned by the correct UIDs before NFS export. This is critical for proper permissions.
Configure NFS Exports#
IMPORTANT: The Synology DSM GUI cannot map to specific UIDs (11000+), so you must configure exports via SSH.
Option 1: Generate Export Rules Automatically (Recommended)#
Use the NFS export generator to create the exact rules you need:
# Interactive mode - prompts for all inputs
cd machine
./generate_nfs_exports.sh
# Direct mode - provide all parameters
./generate_nfs_exports.sh tinsnip test dynamicalsystem ubuntu-machine.local
# Example output shows:
# - Directory creation commands
# - Ownership commands
# - Export rules to add to /etc/exports
# - Test commands
Option 2: Manual Configuration#
- SSH into Synology NAS:
ssh admin@synology-ip
- Edit /etc/exports file:
sudo vi /etc/exports
- Add export rules (CRITICAL: Use TAB characters between path and options):
Use the output from the generator above, or manually create rules like:
/volume1/{sheet}/{service}/{env} {client-host}(rw,async,no_subtree_check,all_squash,anonuid={uid},anongid={uid})
- Reload NFS exports:
sudo exportfs -ra
- Verify exports are active:
sudo exportfs -v
Step 3: Machine Setup#
Install Machine Setup Tools#
The machine setup tools provide automated scripts for creating service users, mounting NFS, and installing rootless Docker.
# One-line installation - downloads scripts to ~/.local/opt/dynamicalsystem.machine
curl -fsSL "https://tangled.sh/dynamicalsystem.com/machine/raw/main/install.sh?$(date +%s)" | bash
# Navigate to installation directory
cd ~/.local/opt/dynamicalsystem.machine
What this installs:
setup.sh- Main orchestration script for service environment creationscripts/- Helper scripts for NFS mounting, Docker installation, etc.machine/- Service-specific setup scripts with sheet support
Run Validations (Optional)#
Before making any system changes, you can optionally validate the setup logic:
cd machine
./validate.sh
Running validations is recommended but not required.
Create Service Environment#
Run the setup script from the machine directory:
Interactive setup (recommended for first time):
cd machine
./setup.sh
# Will prompt for:
# - Service name (tinsnip or gazette)
# - Environment (test or prod)
# - NAS server hostname/IP
Direct setup (if you know the parameters):
cd machine
./setup.sh tinsnip test DS412plus # Creates tinsnip-test environment
./setup.sh gazette prod 192.168.1.100 # Creates gazette-prod environment
# With custom sheet:
TIN_SHEET=mycompany ./setup.sh tinsnip prod nas.mycompany.local
What Gets Created#
The setup creates:
- Service User:
tinsnip-test(UID 11010) with dedicated home directory - NFS Mount:
/mnt/tinsnip-test→DS412plus:/volume1/{sheet}/tinsnip/test - XDG Integration: Symlinks in
~/.local/{state,share,config}/{sheet}/@tinsnip - Rootless Docker: Installed for service user with privileged port support
- Directory Structure:
/mnt/tinsnip-test/ ├── state/ # Service state (logs, history) ├── data/ # Service data files └── config/ # Service configuration
Step 4: Service Deployment#
Switch to Service User#
# Switch to service user context
sudo -u tinsnip-test -i
Deploy Service#
Create service configuration in the mounted NFS directory:
cd /mnt/tinsnip-test
mkdir -p service/lldap
# Create docker-compose.yml for the service
cat > service/lldap/docker-compose.yml << 'EOF'
services:
lldap:
image: lldap/lldap:stable
ports:
- "11010:3890" # LDAP port (UID-based)
- "11011:17170" # Web UI port (UID-based)
volumes:
- ../data:/data
user: "11010:11010" # Run as service UID
environment:
- LLDAP_JWT_SECRET_FILE=/data/jwt_secret
- LLDAP_KEY_SEED_FILE=/data/key_seed
- LLDAP_BASE_DN=dc=home,dc=local
EOF
# Deploy the service
cd service/lldap
docker compose up -d
Step 5: Testing#
Basic Validation#
# Check service user
id tinsnip-test # Should show UID 11010
# Verify NFS mount
mount | grep /mnt/tinsnip-test
ls -la /mnt/tinsnip-test/ # Should show correct ownership
# Check XDG symlinks
ls -la ~/.local/state/dynamicalsystem/@tinsnip # Should point to /mnt/tinsnip-test/state
# Test Docker
sudo -u tinsnip-test docker --version
sudo -u tinsnip-test docker run hello-world
Service Testing#
# Check service status
sudo -u tinsnip-test -i
cd /mnt/tinsnip-test/service/lldap
docker compose ps
# Test service connectivity
curl -I http://localhost:11011 # Web UI
ldapsearch -H ldap://localhost:11010 -b "dc=home,dc=local" # LDAP
VM Testing Plan#
For comprehensive testing, follow the VM Test Plan:
- Function Tests: Validate UID calculation and port allocation
- Partial Tests: Test user creation and NFS connectivity
- Full Setup: Complete service environment creation
- Service Deployment: Deploy and test actual services
Troubleshooting#
NFS Mount Issues#
# Test NFS connectivity manually (adjust path for your sheet)
sudo mount -t nfs DS412plus:/volume1/{sheet}/tinsnip/test /tmp/test-mount
ls -la /tmp/test-mount # Should show UID 11010 ownership
sudo umount /tmp/test-mount
# Check NFS exports on server
ssh admin@DS412plus sudo exportfs -v
Permission Issues#
# Verify UID mapping
sudo -u tinsnip-test touch /mnt/tinsnip-test/test-file
ls -la /mnt/tinsnip-test/test-file # Should show UID 11010
# Check from NAS side (adjust path for your sheet)
ssh admin@DS412plus ls -la /volume1/{sheet}/tinsnip/test/
Docker Issues#
# Check rootless Docker status
sudo -u tinsnip-test systemctl --user status docker
# Test privileged ports
sudo -u tinsnip-test docker run -p 80:80 nginx:alpine
Rollback Plan#
If setup fails or needs to be undone:
# Stop containers
sudo -u tinsnip-test -i bash -c 'docker stop $(docker ps -q)' || true
# Remove service user
sudo pkill -u tinsnip-test || true
sudo userdel -r tinsnip-test
# Unmount NFS
sudo umount /mnt/tinsnip-test || true
sudo rm -rf /mnt/tinsnip-test
# Clean up XDG symlinks (adjust paths for your sheet)
rm -rf ~/.local/state/{sheet}/@tinsnip
rm -rf ~/.local/share/{sheet}/@tinsnip
rm -rf ~/.config/{sheet}/@tinsnip
Security Considerations#
- Each service runs under dedicated UID for complete isolation
- NFS
all_squashensures consistent file ownership - Rootless Docker provides container isolation without root privileges
- Services cannot access each other's data due to UID separation
Next Steps#
After successful machine creation:
- Service Configuration: Configure service-specific settings
- Integration Testing: Test with other tinsnip services
- Monitoring Setup: Add service monitoring and logging
- Backup Validation: Ensure data backup processes work
For service-specific deployment patterns and UID conventions, see DEPLOYMENT_STRATEGY.md.