Skip to Content
Building OsStartup Scripts

Startup Scripts

Run custom commands at first boot to complete system initialization.

How It Works

Startup scripts are executed once when the system first boots. They’re useful for:

  • Initializing applications
  • Fetching configuration from external sources
  • Registering with management systems
  • One-time setup tasks

Script Configuration

Basic Script

{ "startupScripts": [ { "name": "init-app", "script": "#!/bin/bash\necho 'System initialized' > /var/log/init.log" } ] }

Multiple Scripts

{ "startupScripts": [ { "name": "fetch-config", "script": "#!/bin/bash\ncurl -s https://config.example.com/init.sh | bash" }, { "name": "start-services", "script": "#!/bin/bash\nsystemctl enable --now myapp.service" } ] }

Script Options

OptionTypeRequiredDescription
namestringYesScript identifier
scriptstringYesScript content (with shebang)
runAsstringNoUser to run as (default: root)
timeoutnumberNoMax execution time in seconds

Natural Language Examples

Basic Initialization

Add a startup script that creates /var/log/system-ready when the system first boots

Fetch External Configuration

On first boot, fetch configuration from https://config.example.com/node-config.sh and execute it

Multiple Setup Steps

Startup scripts: 1. Download application from S3 2. Extract to /opt/myapp 3. Enable and start myapp service 4. Send registration to management server

Example Scripts

Register with Management Server

#!/bin/bash HOSTNAME=$(hostname) IP=$(ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') curl -X POST https://mgmt.example.com/register \ -H "Content-Type: application/json" \ -d "{\"hostname\": \"$HOSTNAME\", \"ip\": \"$IP\"}"

Initialize Docker Application

#!/bin/bash cd /opt/myapp docker-compose pull docker-compose up -d # Wait for healthy status sleep 30 docker-compose ps

Configure from Cloud Metadata

#!/bin/bash # Fetch instance metadata (AWS example) INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/region) # Configure application cat > /etc/myapp/config.yml << EOF instance_id: $INSTANCE_ID region: $REGION EOF systemctl restart myapp

Set User Password

#!/bin/bash # Generate random password and set for user PASSWORD=$(openssl rand -base64 12) echo "admin:$PASSWORD" | chpasswd # Store password securely for retrieval echo "$PASSWORD" > /root/.initial-password chmod 600 /root/.initial-password

Execution Order

Scripts are executed in the order defined:

  1. First script completes
  2. Second script starts
  3. And so on…

If a script fails, subsequent scripts still run unless you add error handling.

Error Handling

Add error handling to your scripts:

#!/bin/bash set -e # Exit on error download_app() { curl -f -o /opt/app.tar.gz https://releases.example.com/app.tar.gz } if ! download_app; then echo "Failed to download application" >> /var/log/init-error.log exit 1 fi tar -xzf /opt/app.tar.gz -C /opt/

Logging

Script output is captured in system logs:

#!/bin/bash exec 1> >(logger -t init-script -p local0.info) exec 2> >(logger -t init-script -p local0.err) echo "Starting initialization..."

View logs with:

journalctl -t init-script

Security Considerations

  1. Don’t embed secrets - Fetch secrets from secure sources
  2. Validate inputs - Sanitize external data
  3. Use HTTPS - Always use encrypted connections
  4. Minimal permissions - Run scripts as non-root when possible
  5. Audit logging - Log important actions

Cloud-Init Alternative

For cloud deployments, consider using cloud-init instead:

Use cloud-init for first-boot configuration with: - Package updates - SSH key injection - Custom user data script

Cloud-init provides better integration with cloud providers.

Verification

Startup scripts can be tested:

{ "type": "file_contains", "params": { "path": "/var/log/init.log", "content": "System initialized" } }

This verifies the script ran and produced expected output.