diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 85818957ef06207dc6ad53c5431a3857f6ca4e26..6b8aab0e1737a7c2128a4d0e004fcaa9c816ae1c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -28,9 +28,8 @@ test:
   allow_failure: true
   artifacts:
     paths:
-    - obfs4proxy-*.zip
+    - obfs4proxy-*.jar
     - obfs4proxy-*.pom
-    - obfs4proxy-*-sources.jar
     expire_in: 1 week
     when: always
   except:
diff --git a/Dockerfile b/Dockerfile
index 38bcb5260d396f1e3c71ae4f2fb1e10634e9521c..1ed32f355d89efc3664139eb21f8ffb862f9d5ae 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM debian:buster
+FROM debian:bullseye
 
 ARG IGNORE_EXPIRY=0
 ENV LANG=C.UTF-8
@@ -6,14 +6,13 @@ ENV DEBIAN_FRONTEND=noninteractive
 
 WORKDIR /opt/go-reproducer
 
-ADD build-*.py ./
+ADD build-obfs4proxy.py ./
 ADD install*.py ./
 ADD install*.sh ./
 ADD versions.json ./
 ADD utils.py ./
-ADD template.pom ./
-ADD template-android.pom ./
-ADD verify-*.py ./
+ADD template-*.pom ./
+ADD verify-obfs4proxy.py ./
 
 RUN ./install.sh
 
diff --git a/build-obfs4proxy.py b/build-obfs4proxy.py
index 35b44adb627ebe550c2516128752e54f4251a7bf..3b22dceffe9d3f1ddf78870a073c10f3b9188965 100755
--- a/build-obfs4proxy.py
+++ b/build-obfs4proxy.py
@@ -29,17 +29,16 @@ def main():
     # Checkout source at specific version
     checkout_source_repo(versions)
 
-    # Build for various Linux architectures and create package
-    build_linux(versions)
-
-    # Build for various Android architectures and create package
+    # Build and package for various platforms and architectures
     build_android(versions)
-
-    # Package both builds
     package_android(versions)
-    print()
+
+    build_linux(versions)
     package_linux(versions)
 
+    build_windows(versions)
+    package_windows(versions)
+
 
 def install_go(tool_version, versions):
     ex(['./install-go.py', 'obfs4proxy', tool_version])
@@ -82,7 +81,6 @@ def build_android(versions):
 
     env = os.environ.copy()
     env['GOARCH'] = "arm64"
-    env['GOARM'] = "7"
     build_android_arch(versions, env, "aarch64-linux-android", ndk_arch="arm64")
 
     env = os.environ.copy()
@@ -119,17 +117,23 @@ def build_android_arch(versions, env, tool, ndk_arch):
 
 
 def build_linux(versions):
-    build_linux_arch(versions, 'aarch64', 'arm64')
-    build_linux_arch(versions, 'x86_64', 'amd64')
+    build_desktop_arch(versions, 'linux', 'armhf', 'arm', '7')
+    build_desktop_arch(versions, 'linux', 'aarch64', 'arm64')
+    build_desktop_arch(versions, 'linux', 'x86_64', 'amd64')
+
+
+def build_windows(versions):
+    build_desktop_arch(versions, 'windows', 'x86_64', 'amd64')
 
 
-def build_linux_arch(versions, arch, goarch):
+def build_desktop_arch(versions, goos, arch, goarch, goarm=None):
     env = os.environ.copy()
     env['CGO_ENABLED'] = "0"
-    env['GOOS'] = "linux"
+    env['GOOS'] = goos
     env['GOARCH'] = goarch
+    if goarm: env['GOARM'] = goarm
     build_path = os.path.join('.', versions['build_path'])
-    filename = "obfs4proxy_linux-%s.zip" % arch
+    filename = "obfs4proxy_%s-%s.zip" % (goos, arch)
     print("Building %s" % filename)
     ex(['go', 'build', '-ldflags', '-w -s'] + GO_FLAGS + [build_path], env=env, cwd=REPO_DIR)
     zip_files(['obfs4proxy'], filename, versions)
@@ -137,21 +141,34 @@ def build_linux_arch(versions, arch, goarch):
 
 
 def package_android(versions):
-    file_list = ['obfs4proxy_arm_pie.zip', 'obfs4proxy_arm64_pie.zip',
-                 'obfs4proxy_x86_pie.zip', 'obfs4proxy_x86_64_pie.zip']
-    package(versions, file_list, android=True)
+    file_list = [
+        'obfs4proxy_arm_pie.zip',
+        'obfs4proxy_arm64_pie.zip',
+        'obfs4proxy_x86_pie.zip',
+        'obfs4proxy_x86_64_pie.zip'
+    ]
+    package(versions, file_list, 'android')
 
 
 def package_linux(versions):
-    file_list = ['obfs4proxy_linux-aarch64.zip', 'obfs4proxy_linux-x86_64.zip']
-    package(versions, file_list, android=False)
+    file_list = [
+        'obfs4proxy_linux-armhf.zip',
+        'obfs4proxy_linux-aarch64.zip',
+        'obfs4proxy_linux-x86_64.zip'
+    ]
+    package(versions, file_list, 'linux')
+
+
+def package_windows(versions):
+    file_list = ['obfs4proxy_windows-x86_64.zip']
+    package(versions, file_list, 'windows')
 
 
-def package(versions, file_list, android):
-    zip_file = get_final_file_name(versions, android)
+def package(versions, file_list, platform):
+    zip_file = get_final_file_name(versions, platform)
     zip_files(file_list, zip_file, versions)
-    create_sources_jar(versions)
-    create_pom_file(versions, android)
+    create_sources_jar(versions, platform)
+    create_pom_file(versions, platform)
 
     # print hashes for debug purposes
     for file in file_list + [zip_file]:
@@ -160,7 +177,7 @@ def package(versions, file_list, android):
         print("%s %s: %s" % (prefix, file, sha256hash))
 
 
-def create_sources_jar(versions):
+def create_sources_jar(versions, platform):
     # clean all untracked files and directories (-d) from repo
     check_call(['git', 'clean', '-dffx'], cwd=REPO_DIR)
     # vendorize dependencies
@@ -169,16 +186,16 @@ def create_sources_jar(versions):
     for file in glob(os.path.join(REPO_DIR, '*')):
         reset_time(file, versions)
         jar_files.append(os.path.relpath(file, REPO_DIR))
-    jar_file = get_sources_file_name(versions)
+    jar_file = get_sources_file_name(versions, platform)
     jar_path = os.path.abspath(jar_file)
     check_call(['jar', 'cf', jar_path] + jar_files, cwd=REPO_DIR)
     return jar_file
 
 
-def create_pom_file(versions, android=False):
+def create_pom_file(versions, platform):
     tor_version = get_obfs4_version(versions)
-    pom_file = get_pom_file_name(versions, android)
-    template = 'template-android.pom' if android else 'template.pom'
+    pom_file = get_pom_file_name(versions, platform)
+    template = 'template-%s.pom' % platform
     with open(template, 'rt') as infile:
         with open(pom_file, 'wt') as outfile:
             for line in infile:
diff --git a/install.sh b/install.sh
index d58f46c9ff17eeb0b26f34af48792de26be06d44..354face69a845451c1ae50d438940def614980af 100755
--- a/install.sh
+++ b/install.sh
@@ -3,10 +3,9 @@ set -e
 set -x
 
 # use snapshot repos for deterministic package versions
-DATE="20210216T000000Z"
+DATE="20220328T000000Z"
 cat << EOF > /etc/apt/sources.list
-deb http://snapshot.debian.org/archive/debian/${DATE}/ buster main
-deb http://snapshot.debian.org/archive/debian-security/${DATE}/ buster/updates main
+deb http://snapshot.debian.org/archive/debian/${DATE}/ bullseye main
 EOF
 
 # ignore expired package releases if env variable is set
diff --git a/template.pom b/template-linux.pom
similarity index 93%
rename from template.pom
rename to template-linux.pom
index 43017547b762142002377469ee6d737672096d8a..a3b322bd2722ad542d1d9f818c310c4425cea627 100644
--- a/template.pom
+++ b/template-linux.pom
@@ -2,7 +2,8 @@
 <project>
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.briarproject</groupId>
-  <artifactId>obfs4proxy</artifactId>
+  <artifactId>obfs4proxy-linux</artifactId>
+  <name>obfs4proxy-linux</name>
   <version>VERSION</version>
   <url>https://torproject.org</url>
   <description>Repo for building obfs4proxy for Linux.</description>
diff --git a/template-windows.pom b/template-windows.pom
new file mode 100644
index 0000000000000000000000000000000000000000..d499d3cdb3440ef439abce4001b94e01bb8488d7
--- /dev/null
+++ b/template-windows.pom
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.briarproject</groupId>
+  <artifactId>obfs4proxy-windows</artifactId>
+  <name>obfs4proxy-windows</name>
+  <version>VERSION</version>
+  <url>https://torproject.org</url>
+  <description>Repo for building obfs4proxy for Windows.</description>
+  <licenses>
+   <license>
+     <name>BSD-3-clause</name>
+     <url>https://gitweb.torproject.org/pluggable-transports/obfs4.git/tree/LICENSE</url>
+   </license>
+  </licenses>
+  <developers>
+    <developer>
+      <id>yawning</id>
+      <name>Yawning Angel</name>
+      <email>yawning at torproject dot org</email>
+    </developer>
+    <developer>
+      <id>torproject</id>
+      <name>Tor Project</name>
+      <email>frontdesk@rt.torproject.org</email>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:https://git.torproject.org/pluggable-transports/obfs4.git</connection>
+    <developerConnection>scm:git@gitweb.torproject.org/pluggable-transports/obfs4.git</developerConnection>
+    <url>scm:https://gitweb.torproject.org/pluggable-transports/obfs4.git</url>
+  </scm>
+</project>
diff --git a/utils.py b/utils.py
index 9dc75c7206190af7c5fc4abfd3dea297ae3eed12..1d032c603c8165be1c727036b10a3acc89394bc6 100644
--- a/utils.py
+++ b/utils.py
@@ -82,18 +82,18 @@ def get_obfs4_version(versions):
     return versions['tag']
 
 
-def get_file_suffix(versions, android=False):
+def get_file_suffix(versions, platform):
     version = get_obfs4_version(versions)
-    return "%s-%s" % ("android", version) if android else version
+    return "%s-%s" % (platform, version)
 
 
-def get_final_file_name(versions, android=False):
-    return 'obfs4proxy-%s.zip' % get_file_suffix(versions, android)
+def get_final_file_name(versions, platform):
+    return 'obfs4proxy-%s.jar' % get_file_suffix(versions, platform)
 
 
-def get_sources_file_name(versions, android=False):
-    return 'obfs4proxy-%s-sources.jar' % get_file_suffix(versions, android)
+def get_sources_file_name(versions, platform):
+    return 'obfs4proxy-%s-sources.jar' % get_file_suffix(versions, platform)
 
 
-def get_pom_file_name(versions, android=False):
-    return 'obfs4proxy-%s.pom' % get_file_suffix(versions, android)
+def get_pom_file_name(versions, platform):
+    return 'obfs4proxy-%s.pom' % get_file_suffix(versions, platform)
diff --git a/verify-obfs4proxy.py b/verify-obfs4proxy.py
index d1d5c315643242be58e98cc42736ae1d59027a6d..5113b4650e4c1b63c26773e3bdf890740c378b04 100755
--- a/verify-obfs4proxy.py
+++ b/verify-obfs4proxy.py
@@ -11,31 +11,26 @@ def main():
     # get version from command or show usage information
     version = get_version()
 
-    verified = verify(version, for_android=False)
-    verified_android = verify(version, for_android=True)
-    if verified and verified_android:
+    verified_android = verify(version, 'android')
+    verified_linux = verify(version, 'linux')
+    verified_windows = verify(version, 'windows')
+    if verified_android and verified_linux and verified_windows:
         sys.exit(0)
     else:
         sys.exit(1)
 
 
-def verify(version, for_android):
+def verify(version, platform):
     # get version and versions of its dependencies
     tool_version, versions = get_build_versions('obfs4proxy', version)
 
     # download reference binary
-    file_name = get_final_file_name(versions, for_android)
+    file_name = get_final_file_name(versions, platform)
     os.makedirs('reference', exist_ok=True)
     reference_file_name = os.path.join('reference', file_name)
-    try:
-        # try downloading from jcenter
-        check_call(['wget', '--no-verbose', get_url(versions, for_android), '-O',
-                    reference_file_name])
-    except CalledProcessError:
-        # try fallback to bintray
-        print("Warning: Download from jcenter failed. Trying bintray directly...")
-        check_call(['wget', '--no-verbose', get_url(versions, for_android, fallback=True), '-O',
-                    reference_file_name])
+    # try downloading from maven central
+    check_call(['wget', '--no-verbose', get_url(versions, platform), '-O',
+                reference_file_name])
 
     # check if it was already build
     if not os.path.isfile(file_name):
@@ -52,24 +47,19 @@ def verify(version, for_android):
     print("Build sha256:     %s" % build_hash)
 
     # compare hashes
-    suffix = " for Android" if for_android else ""
     if reference_hash == build_hash:
-        print("obfs4proxy%s version %s was successfully verified! \o/" % (suffix, tool_version))
+        print("obfs4proxy-%s version %s was successfully verified! \o/" % (platform, tool_version))
         return True
     else:
-        print("Hashes for obfs4proxy%s version %s do not match! :(" % (suffix, tool_version))
+        print("Hashes for obfs4proxy-%s version %s do not match! :(" % (platform, tool_version))
         return False
 
 
-def get_url(versions, for_android, fallback=False):
+def get_url(versions, platform):
     version = get_obfs4_version(versions)
-    directory = "obfs4proxy-android" if for_android else "obfs4proxy"
-    file = get_final_file_name(versions, for_android)
-    if not fallback:
-        return "https://jcenter.bintray.com/org/briarproject/%s/%s/%s" % (directory, version, file)
-    else:
-        return "https://dl.bintray.com/briarproject/org.briarproject/org/briarproject/%s/%s/%s" % \
-               (directory, version, file)
+    directory = "obfs4proxy-%s" % platform
+    file = get_final_file_name(versions, platform)
+    return "https://repo.maven.apache.org/maven2/org/briarproject/%s/%s/%s" % (directory, version, file)
 
 
 if __name__ == "__main__":
diff --git a/versions.json b/versions.json
index 1bd5761c6db0d327d5b42d7a784e4bd3e466eabf..f486f783769660da0b9af121c24879f57dd1e369 100644
--- a/versions.json
+++ b/versions.json
@@ -1,5 +1,20 @@
 {
   "obfs4proxy": {
+    "0.0.12-release": {
+      "repo_url": "https://git.torproject.org/pluggable-transports/obfs4.git",
+      "revision": "a564bc3840bc788605e1a8155f4b95ce0d70c6db",
+      "build_path": "obfs4proxy",
+      "go": {
+        "version": "go1.16",
+        "sha256": "7688063d55656105898f323d90a79a39c378d86fe89ae192eb3b7fc46347c95a"
+      },
+      "ndk": {
+        "url": "https://dl.google.com/android/repository/android-ndk-r18-linux-x86_64.zip",
+        "revision": "18.0.5002713",
+        "sha256": "c413dd014edc37f822d0dc88fabc05b64232d07d5c6e9345224e47073fdf140b"
+      },
+      "timestamp": "201001010000.00"
+    },
     "0.0.12-dev-40245c4a": {
       "repo_url": "https://git.torproject.org/pluggable-transports/obfs4.git",
       "revision": "40245c4a",