Files
wiki.tipsy.codes/valheim.md
2025-12-18 01:01:43 -08:00

8.4 KiB
Raw Blame History

It turns out that you can run x86 applications on ARM machines, which is super cool. But it requires a bit of nonsense. Here is how I got the Valheim server to work.

Dockerfile

I created a docker file like:

# Use Ubuntu 22.04 as base  
FROM weilbyte/box:debian-11  
  
RUN apt update && apt upgrade -y  
RUN apt install -y curl libpulse-dev libatomic1 libc6  
  
# Create user steam  
RUN useradd -m steam  
  
# Change user to steam  
USER steam  
  
# Go to /home/steam/Steam  
WORKDIR /home/steam/Steam  
  
# Download and extract SteamCMD  
RUN curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf -  
  
RUN /usr/local/bin/box64 /home/steam/Steam/steamcmd.sh +force_install_dir /home/steam/Valheim +login anonymous +app_update 896660 validate +exit  
  
WORKDIR /home/steam/Valheim  
  
COPY start_server.sh /home/steam/Valheim  
  
ENTRYPOINT ["/usr/local/bin/box64", "/home/steam/Valheim/start_server.sh"]

I built and pushed this image with:

docker build -t docker.tipsy.codes/valheim:20251214 .

k3s config

To deploy this, I made added some files to my Flux repo. Here is a tree:

 tree apps/prod/valheim  
apps/prod/valheim  
├── deployment.yaml  
├── ingress.yaml  
├── kustomization.yaml  
├── namespace.yaml  
├── pvc.yaml  
├── pv.yaml  
└── service.yaml  
  
1 directory, 7 files

The most interesting files are:

 find apps/prod/valheim/* -exec echo '# {}' \; -exec cat {} \;  
# apps/prod/valheim/deployment.yaml  
apiVersion: apps/v1  
kind: Deployment  
metadata:  
 name: valheim  
 namespace: valheim  
spec:  
 replicas: 1  
 selector:  
   matchLabels:  
     app: valheim  
 template:  
   metadata:  
     labels:  
       app: valheim  
   spec:  
     containers:  
       - name: valheim  
         image: docker.tipsy.codes/valheim:20251214  
         ports:  
           - containerPort: 2456  
             protocol: UDP  
           - containerPort: 2457  
             protocol: UDP  
           - containerPort: 9001  
             protocol: TCP  
           - containerPort: 80  
             protocol: TCP  
         volumeMounts:  
           - name: valheim-data  
             mountPath: /opt/valheim  
           - name: valheim-config  
             mountPath: /config  
     volumes:  
       - name: valheim-data  
         persistentVolumeClaim:  
           claimName: valheim-pvc  
       - name: valheim-config  
         persistentVolumeClaim:  
           claimName: valheim-config-pvc  
# apps/prod/valheim/ingress.yaml  
apiVersion: traefik.io/v1alpha1  
kind: IngressRouteUDP  
metadata:  
 name: valheim-udp1  
spec:  
 # By default, IngressRouteUDP listens to all UDP entry points if 'entryPoints' is not specified.  
 entryPoints:  
   - valheim-udp1  
 routes:  
   - services:  
       - name: valheim  
         port: 2456 # Replace with your service port  
---  
apiVersion: traefik.io/v1alpha1  
kind: IngressRouteUDP  
metadata:  
 name: valheim-udp2  
spec:  
 # By default, IngressRouteUDP listens to all UDP entry points if 'entryPoints' is not specified.  
 entryPoints:  
   - valheim-udp2  
 routes:  
   - services:  
       - name: valheim  
         port: 2457 # Replace with your service port  
---  
apiVersion: traefik.io/v1alpha1  
kind: IngressRouteTCP  
metadata:  
 name: valheim-tcp1  
spec:  
 # By default, IngressRouteUDP listens to all UDP entry points if 'entryPoints' is not specified.  
 entryPoints:  
   - valheim-tcp1  
 routes:  
   - match: HostSNI(`*`)  
     services:  
       - name: valheim  
         port: 2456 # Replace with your service port  
---  
apiVersion: traefik.io/v1alpha1  
kind: IngressRouteTCP  
metadata:  
 name: valheim-tcp2  
spec:  
 # By default, IngressRouteUDP listens to all UDP entry points if 'entryPoints' is not specified.  
 entryPoints:  
   - valheim-tcp2  
 routes:  
   - match: HostSNI(`*`)  
     services:  
       - name: valheim  
         port: 2457 # Replace with your service port  
# apps/prod/valheim/kustomization.yaml  
apiVersion: kustomize.config.k8s.io/v1beta1  
kind: Kustomization  
resources:  
 - ./namespace.yaml  
 - ./pvc.yaml  
 - ./deployment.yaml  
 - ./service.yaml  
 - ./ingress.yaml  
 - ./pv.yaml  
patches:  
 - patch: |  
     - op: replace  
       path: /metadata/namespace  
       value: valheim  
   target:  
     name: ".*"  
# apps/prod/valheim/namespace.yaml  
apiVersion: v1  
kind: Namespace  
metadata:  
 name: valheim  
# apps/prod/valheim/pvc.yaml  
apiVersion: v1  
kind: PersistentVolumeClaim  
metadata:  
 name: valheim-pvc  
 namespace: valheim  
spec:  
 storageClassName: local-path  
 accessModes:  
   - ReadWriteOnce  
 resources:  
   requests:  
     storage: 100Gi  
 volumeName: valheim-pv  
---  
apiVersion: v1  
kind: PersistentVolumeClaim  
metadata:  
 name: valheim-config-pvc  
 namespace: valheim  
spec:  
 storageClassName: local-path  
 accessModes:  
   - ReadWriteOnce  
 resources:  
   requests:  
     storage: 100Gi  
 volumeName: valheim-config-pv  
# apps/prod/valheim/pv.yaml  
apiVersion: v1  
kind: PersistentVolume  
metadata:  
 name: valheim-pv  
spec:  
 capacity:  
   storage: 100Gi  
 volumeMode: Filesystem  
 accessModes:  
   - ReadWriteOnce  
 persistentVolumeReclaimPolicy: Retain  
 storageClassName: local-path  
 claimRef:  
   namespace: valheim  
   name: valheim-pvc  
 local:  
   path: /var/lib/rancher/k3s/storage/valheim-pvc  
 nodeAffinity:  
   required:  
     nodeSelectorTerms:  
       - matchExpressions:  
           - key: kubernetes.io/hostname  
             operator: In  
             values:  
               - machop  
---  
apiVersion: v1  
kind: PersistentVolume  
metadata:  
 name: valheim-config-pv  
spec:  
 capacity:  
   storage: 100Gi  
 volumeMode: Filesystem  
 accessModes:  
   - ReadWriteOnce  
 persistentVolumeReclaimPolicy: Retain  
 storageClassName: local-path  
 claimRef:  
   namespace: valheim  
   name: valheim-config-pvc  
 local:  
   path: /var/lib/rancher/k3s/storage/valheim-config-pvc  
 nodeAffinity:  
   required:  
     nodeSelectorTerms:  
       - matchExpressions:  
           - key: kubernetes.io/hostname  
             operator: In  
             values:  
               - machop  
# apps/prod/valheim/service.yaml  
apiVersion: v1  
kind: Service  
metadata:  
 name: valheim  
 namespace: valheim  
spec:  
 selector:  
   app: valheim  
 ports:  
   - name: udp-2456  
     protocol: UDP  
     port: 2456  
     targetPort: 2456  
   - name: udp-2457  
     protocol: UDP  
     port: 2457  
     targetPort: 2457  
   - name: tcp-2456  
     protocol: TCP  
     port: 2456  
     targetPort: 2456  
   - name: tcp-2457  
     protocol: TCP  
     port: 2457  
     targetPort: 2457

I did have to make some changes to k3s configuration to open the correct ports:

charles@machop:~/p3/palworld-arm64$ sudo cat /var/lib/rancher/k3s/server/manifests/traefik-config.yaml  
apiVersion: helm.cattle.io/v1  
kind: HelmChartConfig  
metadata:  
 name: traefik  
 namespace: kube-system  
spec:  
 valuesContent: |-  
   ports:  
     websecure:  
       transport:  
         respondingTimeouts:  
           readTimeout: 180m  
     valheim-udp1:  
       port: 2456  
       hostPort: 2456  
       protocol: UDP  
     valheim-udp2:  
       port: 2457  
       hostPort: 2457  
       protocol: UDP  
     valheim-tcp1:  
       port: 2456  
       hostPort: 2456  
       protocol: TCP  
     valheim-tcp2:  
       port: 2457  
       hostPort: 2457  
       protocol: TCP

Does it work?

Yeah, it seems to work. I had some trouble with crossplay, but I have no interest in playing with console peasants anyway.

Happy hunting!