powershell

Hosting Valheim on AWS

Quick introduction for Valheim, it’s an indi game developed by IronGate which is a viking survival game where player can build/craft like minecraft, fight like darksoul and explore a beautiful world like zelda. The game is a huge success with 5 milion players, more information can be found here at Valheim official site.

Below are the steps I took to setup a dedicated server on aws to host valheim:

  1. Spin up an ec2 instance: The game ran pretty smooth with a tiny bit of latency. Below is the instance details:

    • AMI: Ubuntu Server 20.04 LTS (HVM)
    • instance-type: t3a.medium. This is the cheapest we can get. Unfortunately valheim does not support 64bit(Arm) so we can’t use t4 instance type.
    • vpc: we’re using default vpc created by aws on our account.
    • storage: 8gb, the game only require less than 2gb.
    • security group with the folowing rules:
      • Custom TCP Rule: TCP 2456 - 2458 open to our pc ips
      • Custom UDP Rule: UDP 2456 - 2458 open to our pc ips
      • ssh: TCP 22 open to our pc ips
  2. Install Valheim server follow this git repo created by Nimdy: Dedicated_Valheim_Server_Script

  3. Setup cloudwatch to monitor “Network packet out(count)” to stop the instance when it’s not in use after 25 minutes. Valheim server save the world every 20 minutes, this ensure we have the game save whenever we log off:

    • Threshold type: statics
    • Whenever NetworkPacketsOut is: Lower/Equal <= threshold
    • than: 250
    • period: 5 minutes
    • Datapoint to alarm: 5 out of 5
    • treat missing data as missing
  4. Optional: Migrate exisiting world on local computer to valheim server. Coppy the following to files from the below source to valheim server world location: .fwl, .fwl.old, .db. I’m using FileZilla to transfer the file to the ec2 instance.

    • source: C:\Users\YOURNAME\AppData\LocalLow\IronGate\Valheim\worlds
    • valheim server world location: /home/steam/.config/unity3d/IronGate/Valheim/worlds
  5. Run the below script to start the instance and game. (aws powershell module is requrired on the local computer)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    Import-Module AWS.Tools.EC2

    $steam_exe = <steam_exe_location>
    $instance_id = <ec2_valheim_instance_id>
    Set-DefaultAWSRegion -Region <ec2_valheim_instance_region>


    $instance_status = Get-EC2InstanceStatus -InstanceId $instance_id
    if ($instance_status -eq $null){
    Start-EC2Instance -InstanceId $instance_id
    do {
    $instance = (Get-EC2Instance -InstanceId $instance_id).Instances
    Start-Sleep -Seconds 10
    } while ($instance.PublicIpAddress -eq $null)
    } else {
    $instance = (Get-EC2Instance -InstanceId $instance_id).Instances
    }

    $server_ip = $instance.PublicIpAddress

    while ($instance_status.Status.status -ne "ok"){
    Start-Sleep -Seconds 10
    $instance_status = Get-EC2InstanceStatus -InstanceId $instance_id
    $instance_status.Status.status
    }
    if ($instance_status.Status.status -eq "ok"){
    & $steam_exe -applaunch 892970 +connect ${server_ip}:2456
    }

We got this setup running fine for the last 2-3 weeks, and it’s costing us around $1.8 usd. Pretty happy with it, next improvement I guess maybe put together a Terraform for this or if possible, have cloudwatch monitor valheim’s log instead of network packet out count.

Powershell Password Encryption and Decryption

Encrypte and Decrypt credential:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#Create encrypt key
$EncryptKey = New-Object Byte[] 16
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($EncryptKey)
$EncryptKey| Out-File C:\key.txt
#Encrypt credential
$UserCred = Get-Credential
$UserCred.Password | ConvertFrom-SecureString -Key $EncryptedKey | Out-File C:\encrypted.txt

#Decrypt credential
$User = 'TestUser'
$SecureKey = Get-Content C:\Key.txt | ConvertTo-SecureString
$SecurePassword = Get-Content C:\encrypted.txt | ConvertTo-SecureString -SecureKey $SecureKey
$UserCred = New-Object System.Management.Automation.PSCredential ($User, $SecurePassword)
Get-WmiObject -Class win32_OperatingSystem -ComputerName RemoteServerA -Credential $UserCred

Encrypt and Decrypt password:

1
2
3
4
5
6
7
8
$Password = "Password123"
$PasswordBytes = [System.Text.Encoding]::Unicode.GetBytes($Password)
$SecurePassword = [Security.Cryptography.ProtectedData]::Protect($PasswordBytes, $null, [Security.Cryptography.DataProtectionScope]::LocalMachine)
$SecurePasswordStr = [System.Convert]::ToBase64String($SecurePassword)

$SecureStr = [System.Convert]::FromBase64String($SecurePasswordStr)
$StringBytes = [Security.Cryptography.ProtectedData]::Unprotect($SecureStr, $null, [Security.Cryptography.DataProtectionScope]::LocalMachine)
$PasswordStr = [System.Text.Encoding]::Unicode.GetString($StringBytes)

winhttp proxy command

Command to set windows server httpwin proxy setting.

1
netsh winhttp set proxy proxy-server="http=<proxy>:<port>;https=<proxy>:<port>" bypass-list="<local>;<url>"

Powershell script to grab winhttp value

1
2
$ProxyConfig = netsh winhttp show proxy
$Proxy = (((($ProxyConfig | Out-String) -split("`n") |?{$_ -like "*Proxy Server*"}) -split(" ") -split(";")) | ?{$_ -like "http=*"}).Replace("=","://").Trim()