#cloud-config
# Debian 13 Trixie Phoenix/Elixir Web Server Cloud-init
# Optimized for WebSocket and high-concurrency TCP connections

# 1. Install basic tools
packages:
  - curl
  - wget
  - ca-certificates
  - apt-transport-https
  - gnupg
  - fail2ban
  - ufw

# 2. Write installation scripts and config files
write_files:
  # Docker installation script
  - path: /root/install-docker.sh
    content: |
      #!/bin/bash
      set -e

      echo "Starting Docker installation..."

      # Install prerequisites
      apt-get update
      apt-get install -y ca-certificates curl gnupg lsb-release

      # Add Docker GPG key
      install -m 0755 -d /etc/apt/keyrings
      curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
      chmod a+r /etc/apt/keyrings/docker.gpg

      # Add Docker repository (Debian 13 Trixie)
      echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian trixie stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

      # Install Docker
      apt-get update
      apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

      # Enable and start Docker
      systemctl enable --now docker

      echo "Docker installation completed"
    permissions: '0755'
    owner: root:root

  # Kernel parameter tuning for Phoenix/WebSocket
  - path: /etc/sysctl.d/99-phoenix-optimize.conf
    content: |
      # ============================================================================
      # Phoenix/Elixir Web Server Kernel Parameter Tuning
      # Optimized for WebSocket and high-concurrency TCP connections
      # ============================================================================

      # ============================================================================
      # 1. File Descriptor Limits (Critical for WebSocket)
      # ============================================================================
      # Each WebSocket connection uses one file descriptor.
      # With LiveView, connections stay open for long periods.
      # Increase system-wide limit for high concurrent connections.
      fs.file-max = 524288

      # ============================================================================
      # 2. TCP Connection Tuning
      # ============================================================================
      # somaxconn: TCP listen queue length. Default 128 is too small.
      # Phoenix/Cowboy uses this for incoming connections.
      net.core.somaxconn = 65535

      # tcp_max_syn_backlog: SYN queue for burst connections.
      # Increase for servers with many simultaneous new connections.
      net.ipv4.tcp_max_syn_backlog = 16384

      # tcp_fin_timeout: Reduce TIME_WAIT socket hold time.
      # Helps free resources faster for high-throughput servers.
      net.ipv4.tcp_fin_timeout = 15

      # tcp_tw_reuse: Reuse TIME_WAIT sockets for new connections.
      net.ipv4.tcp_tw_reuse = 1

      # tcp_max_tw_buckets: Limit TIME_WAIT socket count.
      net.ipv4.tcp_max_tw_buckets = 200000

      # tcp_keepalive: Detect dead connections faster (important for WebSocket).
      net.ipv4.tcp_keepalive_time = 300
      net.ipv4.tcp_keepalive_intvl = 30
      net.ipv4.tcp_keepalive_probes = 5

      # ============================================================================
      # 3. Socket Buffer Tuning
      # ============================================================================
      # Increase socket buffer sizes for better throughput.
      net.core.rmem_default = 262144
      net.core.rmem_max = 16777216
      net.core.wmem_default = 262144
      net.core.wmem_max = 16777216

      # TCP buffer sizes (min, default, max).
      # Format: min, default, max
      net.ipv4.tcp_rmem = 4096 87380 16777216
      net.ipv4.tcp_wmem = 4096 65536 16777216

      # ============================================================================
      # 4. Connection Tracking (Optional - only if needed)
      # ============================================================================
      # Increase conntrack table size if using any proxy/forwarding.
      # Not typically needed for pure Phoenix apps.
      net.netfilter.nf_conntrack_max = 262144
      net.netfilter.nf_conntrack_hashsize = 65536

      # ============================================================================
      # 5. Security: Disable ICMP Redirects
      # ============================================================================
      net.ipv4.conf.all.accept_redirects = 0
      net.ipv4.conf.default.accept_redirects = 0
      net.ipv6.conf.all.accept_redirects = 0
      net.ipv6.conf.default.accept_redirects = 0

      # ============================================================================
      # 6. Security: Disable Source Routing
      # ============================================================================
      net.ipv4.conf.all.send_redirects = 0
      net.ipv4.conf.default.send_redirects = 0

      # ============================================================================
      # 7. IP Local Port Range
      # ============================================================================
      # Increase ephemeral port range for more outgoing connections.
      # Format: low, high
      net.ipv4.ip_local_port_range = 10240 65535
    owner: root:root
    permissions: '0644'

  # Increase system file descriptor limits
  - path: /etc/security/limits.d/phoenix.conf
    content: |
      # ============================================================================
      # Increase file descriptor limits for Phoenix/Elixir
      # Each WebSocket connection uses ~1 FD
      # ============================================================================

      # Soft limit for max open files
      * soft nofile 524288

      # Hard limit for max open files
      * hard nofile 524288

      # For root user (needed for some system operations)
      root soft nofile 524288
      root hard nofile 524288

      # Max processes (Elixir uses many processes)
      * soft nproc 65535
      * hard nproc 65535
    owner: root:root
    permissions: '0644'

  # Phoenix systemd service limits
  - path: /etc/systemd/system/phoenix.service.d/limits.conf
    content: |
      [Service]
      # Increase file descriptor limit for Phoenix application
      LimitNOFILE=524288

      # Increase max processes (Elixir lightweight processes)
      LimitNPROC=65535
    owner: root:root
    permissions: '0644'

  # SSH port change script
  - path: /root/ssh-port-change.sh
    content: |
      #!/bin/bash
      sed -i 's/^#Port 22/Port 22022/' /etc/ssh/sshd_config
      sed -i 's/^Port 22/Port 22022/' /etc/ssh/sshd_config
      # Only listen on new port
      echo "ListenAddress 0.0.0.0" >> /etc/ssh/sshd_config
      systemctl restart sshd
    permissions: '0755'
    owner: root:root

  # Weekly auto-update script
  - path: /root/auto-update.sh
    content: |
      #!/bin/bash
      # Weekly auto-update script for security patches

      echo "========== $(date) Starting system update ==========" >> /var/log/auto-update.log 2>&1
      apt-get update >> /var/log/auto-update.log 2>&1
      apt-get upgrade -y >> /var/log/auto-update.log 2>&1
      echo "========== $(date) Update completed ==========" >> /var/log/auto-update.log 2>&1
    permissions: '0755'
    owner: root:root

# 3. Commands to run on first boot
runcmd:
  # Enable and configure UFW firewall
  - ufw --force reset
  - ufw default deny incoming
  - ufw default allow outgoing
  - ufw allow 22022/tcp comment 'SSH'
  - ufw allow 443/tcp comment 'HTTPS'
  - ufw allow 80/tcp comment 'HTTP'
  - ufw --force enable

  # Enable fail2ban
  - systemctl enable --now fail2ban

  # Change SSH port to 22022
  - /root/ssh-port-change.sh

  # Apply kernel parameters
  - sysctl -p /etc/sysctl.d/99-phoenix-optimize.conf

  # Reload systemd to pick up new limits config
  - systemctl daemon-reload

  # Install Docker
  - /root/install-docker.sh

  # Set script permissions
  - chmod +x /root/auto-update.sh

  # Add cron job: Every Monday at 2:00 AM
  - |
    echo "0 2 * * 1 /root/auto-update.sh" >> /etc/crontab

  # Enable docker service
  - systemctl enable docker || true

# 4. Timezone
timezone: Asia/Singapore
