diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
new file mode 100644
index 0000000..19af02b
--- /dev/null
+++ b/.github/workflows/build.yaml
@@ -0,0 +1,67 @@
+name: Go Build & Test
+on:
+  push:
+    branches:
+      - master
+    tags:
+      - '**'
+  pull_request:
+  workflow_dispatch:
+
+jobs:
+  build-and-test:
+    runs-on: ubuntu-latest
+
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}
+      cancel-in-progress: true
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+
+      - name: Login to Docker Hub
+        uses: docker/login-action@v3
+        if: github.event_name != 'pull_request'
+        with:
+          username: ${{ vars.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+      - name: Set up Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: stable
+
+      - name: Build and run tests
+        run: |
+          go install ./...
+          go test -short -v ./...
+          _script/run-e2e.sh read
+
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v3
+
+      - name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v3
+
+      - name: Docker meta
+        id: meta
+        uses: docker/metadata-action@v5
+        with:
+          images: |
+            docker.io/${{ github.repository }}
+          tags: |
+            type=edge
+            type=ref,event=branch
+            type=semver,pattern={{version}}
+            type=semver,pattern={{major}}.{{minor}}
+            type=semver,pattern={{major}}
+            type=sha
+
+      - name: Build and push
+        uses: docker/build-push-action@v6
+        with:
+          platforms: linux/amd64,linux/arm64
+          push: ${{ github.event_name != 'pull_request' }}
+          tags: ${{ steps.meta.outputs.tags }}
+          labels: ${{ steps.meta.outputs.labels }}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 1025c8b..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-dist: focal
-language: go
-go:
-  - 1.21.x
-services:
-  - docker
-env:
-  global:
-    - CGO_ENABLED=0
-gobuild_args: -a -tags netgo -ldflags '-w'
-go_import_path: github.com/adevinta/vulnerability-db-api
-script:
-  - go install ./...
-  - go test -short -v $(go list ./... | grep -v /vendor/)
-  - _script/run-e2e.sh read
-after_success:
-  - bash -c 'source <(curl -s https://raw.githubusercontent.com/adevinta/vulcan-cicd/master/docker.sh)'
diff --git a/Dockerfile b/Dockerfile
index d6ddddd..819182e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,11 @@
 # Copyright 2020 Adevinta
 
-FROM golang:1.22-alpine3.18 as builder
+FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder
 
 WORKDIR /app
 
+ARG TARGETOS TARGETARCH
+
 COPY go.mod .
 COPY go.sum .
 
@@ -11,7 +13,7 @@ RUN go mod download
 
 COPY . .
 
-RUN cd cmd/vulnerability-db-api/ && GOOS=linux GOARCH=amd64 go build . && cd -
+RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build ./cmd/vulnerability-db-api
 
 FROM alpine:3.21
 
@@ -19,13 +21,7 @@ RUN apk add --no-cache --update bash gettext
 
 WORKDIR /app
 
-ARG BUILD_RFC3339="1970-01-01T00:00:00Z"
-ARG COMMIT="local"
-
-ENV BUILD_RFC3339 "$BUILD_RFC3339"
-ENV COMMIT "$COMMIT"
-
-COPY --from=builder /app/cmd/vulnerability-db-api/vulnerability-db-api .
+COPY --from=builder /app/vulnerability-db-api .
 
 COPY config.toml .
 COPY run.sh .
diff --git a/_resources/postgres-start.sh b/_resources/postgres-start.sh
index 52ef117..7b06f81 100644
--- a/_resources/postgres-start.sh
+++ b/_resources/postgres-start.sh
@@ -2,4 +2,4 @@
 
 # Copyright 2020 Adevinta
 
-docker-compose up -d
+docker compose up -d
diff --git a/_resources/postgres-stop.sh b/_resources/postgres-stop.sh
index 951e44b..16dfe25 100644
--- a/_resources/postgres-stop.sh
+++ b/_resources/postgres-stop.sh
@@ -2,5 +2,5 @@
 
 # Copyright 2020 Adevinta
 
-docker-compose kill
-docker-compose rm -f
+docker compose kill
+docker compose rm -f
diff --git a/_script/run-e2e.sh b/_script/run-e2e.sh
index 0654ee9..e0db0a9 100755
--- a/_script/run-e2e.sh
+++ b/_script/run-e2e.sh
@@ -34,7 +34,7 @@ case $ARG in
 esac
 
 # Start postgress databases.
-docker-compose -f _resources/docker-compose-e2e.yml -p e2e up --quiet-pull -d $SERVICE
+docker compose -f _resources/docker-compose-e2e.yml -p e2e up --quiet-pull -d $SERVICE
 
 # Set up schema for the test db.
 VDB=$(mktemp -d)
@@ -60,10 +60,10 @@ vulnerability-db-api -c $CONFIG_FILE &
 
 # Run e2e tests.
 echo "RUNNING e2e tests"
-docker-compose -f _resources/docker-compose-e2e.yml -p "e2e" run e2e
+docker compose -f _resources/docker-compose-e2e.yml -p "e2e" run --quiet-pull e2e
 
 # Clean up resurces.
 set +e
 pkill vulnerability-db-api
 set -e
-docker-compose -f _resources/docker-compose-e2e.yml  -p "e2e" rm -s -f -v
+docker compose -f _resources/docker-compose-e2e.yml -p "e2e" rm -s -f -v
diff --git a/go.mod b/go.mod
index 1859535..211779d 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,7 @@
 module github.com/adevinta/vulnerability-db-api
 
-go 1.21.2
+go 1.23.0
+
 toolchain go1.24.1
 
 require (