diff --git a/group_vars/all/geo.yml b/group_vars/all/geo.yml
index 92df9c5f3e9200b4db4107ebd32e1dc9934a2ac5..70575fcbd09e82ed5a04ca00b00a00246a24b6a2 100644
--- a/group_vars/all/geo.yml
+++ b/group_vars/all/geo.yml
@@ -1,7 +1,10 @@
 geo_acme_dns_challenge_ns: redirect.archlinux.org
 geo_domains:
   - geo.mirror.pkgbuild.com
+  - riscv.mirror.pkgbuild.com
 # geo_options.*.hosts defaults to "{{ groups['geo_mirrors'] }}"
 geo_options:
   geo.mirror.pkgbuild.com:
     health_check_path: /lastupdate
+  riscv.mirror.pkgbuild.com:
+    health_check_path: /.status/lastupdate.txt
diff --git a/group_vars/geo_mirrors/misc.yml b/group_vars/geo_mirrors/misc.yml
index 1989aae0588276104b5317c0d1362059b7b2b398..ddfaa2e00d3d9fb67a8f2c244e09c44a91ffb7ff 100644
--- a/group_vars/geo_mirrors/misc.yml
+++ b/group_vars/geo_mirrors/misc.yml
@@ -1,2 +1,3 @@
 certbot_dns_support: true
-geo_mirror_domain: "geo.mirror.pkgbuild.com"
+geo_mirror_domain: geo.mirror.pkgbuild.com
+riscv_mirror_domain: riscv.mirror.pkgbuild.com
diff --git a/playbooks/mirrors.yml b/playbooks/mirrors.yml
index f3a2cd58cb35a3fc234d7e3ba039d80f37669803..3d1dbda5092bb2c4eb867a149db140d7858e0d6e 100644
--- a/playbooks/mirrors.yml
+++ b/playbooks/mirrors.yml
@@ -11,6 +11,7 @@
     - { role: nginx }
     - { role: syncrepo, tags: ['nginx'] }
     - { role: syncdebug, when: mirror_debug_packages is not defined or mirror_debug_packages }
+    - { role: syncriscv, when: riscv_mirror_domain is defined }
     - { role: archweb, when: archweb_mirrorcheck_locations is defined, archweb_site: false, archweb_services: false, archweb_mirrorcheck: true }
     - { role: prometheus_exporters }
     - { role: promtail }
diff --git a/roles/prometheus/defaults/main.yml b/roles/prometheus/defaults/main.yml
index f8ae923c609591a773f85481e3ec4a253443516b..6e6a1199b0b8ec2a485d07891ebcb2b740edba43 100644
--- a/roles/prometheus/defaults/main.yml
+++ b/roles/prometheus/defaults/main.yml
@@ -16,6 +16,9 @@ blackbox_targets:
     - targets: "{{ groups['geo_mirrors'] }}"
       hostname: geo.mirror.pkgbuild.com
       secure: true
+    - targets: "{{ groups['geo_mirrors'] }}"
+      hostname: riscv.mirror.pkgbuild.com
+      secure: true
     - http://{{ hostvars['monitoring.archlinux.org']['wireguard_address'] }}
 
     # regenerate the list below with: ./misc/find-arch-on-crt.sh targets
@@ -83,6 +86,8 @@ blackbox_targets:
     - lists.archlinux.org:25
   geo_dns_geo.mirror.pkgbuild.com_a: "{{ groups['geo_mirrors'] }}"
   geo_dns_geo.mirror.pkgbuild.com_aaaa: "{{ groups['geo_mirrors'] }}"
+  geo_dns_riscv.mirror.pkgbuild.com_a: "{{ groups['geo_mirrors'] }}"
+  geo_dns_riscv.mirror.pkgbuild.com_aaaa: "{{ groups['geo_mirrors'] }}"
 matrix_metrics_endpoints:
   - homeserver
   - appservice
diff --git a/roles/syncriscv/files/syncriscv b/roles/syncriscv/files/syncriscv
new file mode 100755
index 0000000000000000000000000000000000000000..b1116bf3aaa2271d7d886bbf40bc2a729cef49ce
--- /dev/null
+++ b/roles/syncriscv/files/syncriscv
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+target="/srv/riscv"
+lock="/var/lock/syncriscv.lck"
+source_url='rsync://archriscv.felixc.at/archriscv'
+lastupdate_url='https://archriscv.felixc.at/.status/lastupdate.txt'
+
+[ ! -d "${target}" ] && mkdir -p "${target}"
+
+exec 9>"${lock}"
+flock -n 9 || exit
+
+rsync_cmd() {
+	local -a cmd=(rsync -rlptH --safe-links --delete-delay --delay-updates
+		"--timeout=600" "--contimeout=60" --no-motd)
+
+	if stty &>/dev/null; then
+		cmd+=(-h -v --progress)
+	else
+		cmd+=("--info=name1")
+	fi
+
+	"${cmd[@]}" "$@"
+}
+
+# if we are called without a tty (cronjob) only run when there are changes
+if ! tty -s && [[ -f "$target/.status/lastupdate.txt" ]] && diff -b <(curl -Ls "$lastupdate_url") "$target/.status/lastupdate.txt" >/dev/null; then
+	exit 0
+fi
+
+rsync_cmd "${source_url}" "${target}"
diff --git a/roles/syncriscv/files/syncriscv.service b/roles/syncriscv/files/syncriscv.service
new file mode 100644
index 0000000000000000000000000000000000000000..2426f9ff94c8eb431993f799c6b9f158d5c3f8c9
--- /dev/null
+++ b/roles/syncriscv/files/syncriscv.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Synchronize RISC-V mirror
+RequiresMountsFor=/srv/riscv
+Wants=network-online.target
+After=network-online.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/local/bin/syncriscv
+Nice=19
+IOSchedulingClass=best-effort
+IOSchedulingPriority=7
diff --git a/roles/syncriscv/files/syncriscv.timer b/roles/syncriscv/files/syncriscv.timer
new file mode 100644
index 0000000000000000000000000000000000000000..b944e78451f3fb7d376d3429cb5ccd1056bcb355
--- /dev/null
+++ b/roles/syncriscv/files/syncriscv.timer
@@ -0,0 +1,10 @@
+[Unit]
+Description=Minutely RISC-V mirror sync
+
+[Timer]
+OnCalendar=minutely
+AccuracySec=1m
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/roles/syncriscv/tasks/main.yml b/roles/syncriscv/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9c8612bccb3bb8616511920ae808360abf7ae9ab
--- /dev/null
+++ b/roles/syncriscv/tasks/main.yml
@@ -0,0 +1,29 @@
+- name: Create ssl cert
+  include_role:
+    name: certificate
+  vars:
+    domains: ["{{ riscv_mirror_domain }}"]
+    challenge: "DNS-01"
+
+- name: Install rsync
+  pacman: name=rsync state=present
+
+- name: Install syncriscv script
+  copy: src=syncriscv dest=/usr/local/bin/syncriscv owner=root group=root mode=0755
+
+- name: Install syncriscv units
+  copy: src={{ item }} dest=/etc/systemd/system/{{ item }} owner=root group=root mode=0644
+  with_items:
+    - syncriscv.timer
+    - syncriscv.service
+
+- name: Start and enable syncriscv timer
+  systemd: name=syncriscv.timer enabled=yes state=started daemon_reload=yes
+
+- name: Set up nginx
+  template: src=nginx.d.conf.j2 dest=/etc/nginx/nginx.d/riscv.conf owner=root group=root mode=0644
+  notify: Reload nginx
+  tags: ['nginx']
+
+- name: Make nginx log dir
+  file: path=/var/log/nginx/{{ riscv_mirror_domain }} state=directory owner=root group=root mode=0755
diff --git a/roles/syncriscv/templates/nginx.d.conf.j2 b/roles/syncriscv/templates/nginx.d.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..07a116d8d362c9c7420506c234cf718ec42b3119
--- /dev/null
+++ b/roles/syncriscv/templates/nginx.d.conf.j2
@@ -0,0 +1,22 @@
+server {
+    listen       80;
+    listen       [::]:80;
+    listen       443 ssl http2;
+    listen       [::]:443 ssl http2;
+    server_name  {{ riscv_mirror_domain }};
+    root         /srv/riscv;
+
+    access_log   /var/log/nginx/{{ riscv_mirror_domain }}/access.log reduced;
+    access_log   /var/log/nginx/{{ riscv_mirror_domain }}/access.log.json json_reduced;
+    error_log    /var/log/nginx/{{ riscv_mirror_domain }}/error.log;
+
+    include snippets/letsencrypt.conf;
+
+    ssl_certificate      /etc/letsencrypt/live/{{ riscv_mirror_domain }}/fullchain.pem;
+    ssl_certificate_key  /etc/letsencrypt/live/{{ riscv_mirror_domain }}/privkey.pem;
+    ssl_trusted_certificate /etc/letsencrypt/live/{{ riscv_mirror_domain }}/chain.pem;
+
+    add_header X-Served-By "{{ inventory_hostname }}";
+
+    autoindex on;
+}
diff --git a/tf-stage1/archlinux.tf b/tf-stage1/archlinux.tf
index 0aaa9823fd5891856ef2be2e348235c8b07071b2..e9eae05d4310805dbdafdd3c75552cadbc8db337 100644
--- a/tf-stage1/archlinux.tf
+++ b/tf-stage1/archlinux.tf
@@ -409,6 +409,10 @@ locals {
       name = "geo.mirror"
       zone = hetznerdns_zone.pkgbuild.id
     }
+    "riscv.mirror.pkgbuild.com" = {
+      name = "riscv.mirror"
+      zone = hetznerdns_zone.pkgbuild.id
+    }
   }
 }