├── .gitignore ├── .gitmodules ├── wireguard-fs ├── data │ ├── pre_up.sh │ └── healthcheck.sh └── etc │ ├── iproute2 │ └── rt_tables │ └── init.d │ └── wg-quick ├── docker-compose.yml ├── Makefile ├── .github └── workflows │ └── ci-build.yml ├── Dockerfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | wg/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "amneziawg-go"] 2 | path = amneziawg-go 3 | url = https://github.com/amnezia-vpn/amneziawg-go.git 4 | -------------------------------------------------------------------------------- /wireguard-fs/data/pre_up.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # create /dev/net/tun if it does not exist 4 | if [[ ! -c /dev/net/tun ]]; then 5 | mkdir -p /dev/net && mknod /dev/net/tun c 10 200 6 | fi 7 | -------------------------------------------------------------------------------- /wireguard-fs/etc/iproute2/rt_tables: -------------------------------------------------------------------------------- 1 | # 2 | # reserved values 3 | # 4 | 255 local 5 | 254 main 6 | 253 default 7 | 0 unspec 8 | # 9 | # local 10 | # 11 | #1 inr.ruhep 12 | 100 to_internet 13 | 101 aux1 14 | 102 aux2 -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | wireguard: 4 | image: awg-docker 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | cap_add: 9 | - NET_ADMIN 10 | - SYS_MODULE 11 | # network_mode: host 12 | sysctls: 13 | net.ipv4.conf.all.src_valid_mark: 1 14 | ports: 15 | - 51820:51820/udp 16 | volumes: 17 | - ./wg:/etc/wireguard 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | awg-arm7: 2 | cd amnezia-wg; make clean; GOOS=linux GOARCH=arm GOARM=7 make; cd .. 3 | awg-mips: 4 | cd amnezia-wg; make clean; GOOS=linux GOARCH=mipsle GOMIPS=softfloat make; cd .. 5 | 6 | build-arm7: awg-arm7 7 | DOCKER_BUILDKIT=1 docker buildx build --no-cache --platform linux/arm/v7 --output=type=docker --tag docker-awg:latest . 8 | 9 | export-arm7: build-arm7 10 | docker save docker-awg:latest > docker-awg-arm7.tar 11 | 12 | -------------------------------------------------------------------------------- /wireguard-fs/data/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | 4 | # Container healthcheck script 5 | mapfile -t wg_elements < <( /usr/bin/awg ) 6 | 7 | if [ ${#wg_elements[@]} -gt 5 ]; then 8 | for key in "${!wg_elements[@]}"; do 9 | if [[ ${wg_elements[$key]} =~ "peer:" ]] || [[ ${wg_elements[$key]} =~ "handshake:" ]]; then 10 | printf " ${wg_elements[$key]}:"; 11 | fi 12 | done 13 | exit 0; 14 | else 15 | echo "awg not started" 16 | exit 1; 17 | fi 18 | -------------------------------------------------------------------------------- /wireguard-fs/etc/init.d/wg-quick: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | 3 | description="Amnezia WG Quick Up" 4 | 5 | depend() { 6 | need localmount 7 | need net 8 | } 9 | 10 | start_pre() 11 | { 12 | /data/pre_up.sh 13 | } 14 | 15 | start() { 16 | for file in $(grep '\[Interface\]' /etc/amnezia/amneziawg/*.conf -l 2>/dev/null); do 17 | interface=$(basename $file .conf) 18 | ebegin "Starting Amnezia WG interface $interface" 19 | /usr/bin/awg-quick up $file 20 | done 21 | eend 0 22 | } 23 | 24 | stop() { 25 | for file in $(grep '\[Interface\]' /etc/amnezia/amneziawg/*.conf -l 2>/dev/null); do 26 | interface=$(basename $file .conf) 27 | ebegin "Starting Amnezia WG interface $interface" 28 | /usr/bin/awg-quick down $file 29 | done 30 | eend 0 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/ci-build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | pull_request: 9 | 10 | jobs: 11 | build-images: 12 | name: Build Docker images 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: set up QEMU 19 | uses: docker/setup-qemu-action@v3 20 | 21 | - name: set up Docker Buildx 22 | id: buildx 23 | uses: docker/setup-buildx-action@v3 24 | 25 | - name: available platforms 26 | run: echo ${{ steps.buildx.outputs.platforms }} 27 | 28 | - name: build amnezia-wg-docker image without pushing (only outside master) 29 | if: ${{ github.ref != 'refs/heads/master' }} 30 | run: | 31 | docker buildx build \ 32 | --platform linux/arm/v7 . 33 | 34 | - name: build amnezia-wg-docker image for ghcr.io 35 | if: ${{ github.ref == 'refs/heads/master' }} 36 | env: 37 | GITHUB_PACKAGE_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | USERNAME: ${{ github.actor }} 39 | run: | 40 | echo ${GITHUB_PACKAGE_TOKEN} | docker login ghcr.io -u ${USERNAME} --password-stdin 41 | docker buildx build --push \ 42 | --platform linux/arm/v7 \ 43 | -t ghcr.io/yury-sannikov/amnezia-wg-docker:latest . 44 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG GOLANG_VERSION=1.21 2 | ARG ALPINE_VERSION=3.19 3 | FROM golang:${GOLANG_VERSION}-alpine${ALPINE_VERSION} AS builder 4 | 5 | RUN apk update && apk add --no-cache git make bash build-base linux-headers 6 | RUN git clone https://github.com/amnezia-vpn/amneziawg-tools.git 7 | RUN cd amneziawg-tools/src && \ 8 | make 9 | 10 | FROM alpine:${ALPINE_VERSION} 11 | RUN apk update && apk add --no-cache bash openrc iptables iptables-legacy iproute2 12 | COPY amnezia-wg/amneziawg-go /usr/bin/amneziawg-go 13 | COPY --from=builder /go/amneziawg-tools/src/wg /usr/bin/awg 14 | COPY --from=builder /go/amneziawg-tools/src/wg-quick/linux.bash /usr/bin/awg-quick 15 | COPY wireguard-fs / 16 | 17 | RUN \ 18 | sed -i 's/^\(tty\d\:\:\)/#\1/' /etc/inittab && \ 19 | sed -i \ 20 | -e 's/^#\?rc_env_allow=.*/rc_env_allow="\*"/' \ 21 | -e 's/^#\?rc_sys=.*/rc_sys="docker"/' \ 22 | /etc/rc.conf && \ 23 | sed -i \ 24 | -e 's/VSERVER/DOCKER/' \ 25 | -e 's/checkpath -d "$RC_SVCDIR"/mkdir "$RC_SVCDIR"/' \ 26 | /lib/rc/sh/init.sh && \ 27 | rm \ 28 | /etc/init.d/hwdrivers \ 29 | /etc/init.d/machine-id 30 | RUN sed -i 's/cmd sysctl -q \(.*\?\)=\(.*\)/[[ "$(sysctl -n \1)" != "\2" ]] \&\& \0/' /usr/bin/awg-quick 31 | RUN \ 32 | ln -s /sbin/iptables-legacy /bin/iptables && \ 33 | ln -s /sbin/iptables-legacy-save /bin/iptables-save && \ 34 | ln -s /sbin/iptables-legacy-restore /bin/iptables-restore 35 | # register /etc/init.d/wg-quick 36 | RUN rc-update add wg-quick default 37 | 38 | 39 | VOLUME ["/sys/fs/cgroup"] 40 | HEALTHCHECK --interval=15m --timeout=30s CMD /bin/bash /data/healthcheck.sh 41 | CMD ["/sbin/init"] 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## About The Project 2 | Mikrotik compatible Docker image to run Amnezia WG on Mikrotik routers. As of now, support Arm v7 boards 3 | 4 | ## About The Project 5 | This is a highly experimental attempt to run [Amnezia-WG](https://github.com/amnezia-vpn/amnezia-wg) on a Mikrotik router. 6 | 7 | ### Prerequisites 8 | 9 | Follow the [Mikrotik guidelines](https://help.mikrotik.com/docs/display/ROS/Container) to enable container support. 10 | 11 | Install [Docker buildx](https://github.com/docker/buildx) subsystem, make and go. 12 | 13 | 14 | ### Building Docker Image 15 | 16 | You may need to initialize submodules 17 | 18 | ``` 19 | git submodule init 20 | git submodule update 21 | ``` 22 | 23 | To build a Docker container for the ARM7 run 24 | ``` 25 | make build-arm7 26 | ``` 27 | This command should cross-compile amnezia-wg locally and then build a docker image for ARM7 arch. 28 | 29 | To export a generated image, use 30 | ``` 31 | make export-arm7 32 | ``` 33 | 34 | You will get the `docker-awg-arm7.tar` archive ready to upload to the Mikrotik router. 35 | 36 | ### Running locally 37 | 38 | Just run `docker compose up` 39 | 40 | Make sure to create a `awg` folder with the `wg0.conf` file. 41 | 42 | Example `wg0.conf`: 43 | 44 | ``` 45 | [Interface] 46 | PrivateKey = gG...Y3s= 47 | Address = 10.0.0.1/32 48 | ListenPort = 51820 49 | # Jc лучше брать в интервале [3,10], Jmin = 100, Jmax = 1000, 50 | Jc = 3 51 | Jmin = 100 52 | Jmax = 1000 53 | # Parameters below will not work with the existing WireGuarg implementation. 54 | # Use if your peer running Amnesia-WG 55 | # S1 = 324 56 | # S2 = 452 57 | # H1 = 25 58 | 59 | # IP masquerading 60 | PreUp = iptables -t nat -A POSTROUTING ! -o %i -j MASQUERADE 61 | # Firewall wg peers from other hosts 62 | PreUp = iptables -A FORWARD -o %i -m state --state ESTABLISHED,RELATED -j ACCEPT 63 | PreUp = iptables -A FORWARD -o %i -j REJECT 64 | 65 | # Remote settings for my workstation 66 | [Peer] 67 | PublicKey = wx...U= 68 | AllowedIPs = 10.0.0.2/32 69 | # An IP address to check peer connectivity (specific to this repo) 70 | TestIP = 10.0.0.2 71 | # Your existing Wireguard server 72 | Endpoint=xx.xx.xx.xx:51820 73 | PersistentKeepalive = 25 74 | 75 | ``` 76 | 77 | ### Mikrotik Configuration 78 | 79 | Set up interface and IP address for the containers 80 | 81 | ``` 82 | /interface bridge 83 | add name=containers 84 | 85 | /interface veth 86 | add address=172.17.0.2/24 gateway=172.17.0.1 gateway6="" name=veth1 87 | 88 | /interface bridge port 89 | add bridge=containers interface=veth1 90 | 91 | /ip address 92 | add address=172.17.0.1/24 interface=containers network=172.17.0.0 93 | ``` 94 | Set up masquerading for the outgoing traffic and dstnat 95 | 96 | ``` 97 | /ip firewall nat 98 | add action=masquerade chain=srcnat comment="Outgoing NAT for containers" src-address=172.17.0.0/24 99 | /ip firewall nat 100 | add action=dst-nat chain=dstnat comment=amnezia-wg dst-port=51820 protocol=udp to-addresses=172.17.0.2 to-ports=51820 101 | ``` 102 | 103 | Set up mount with the Wireguard configuration 104 | 105 | ``` 106 | /container mounts 107 | add dst=/etc/amnezia/amneziawg/ name=awg_config src=/awg 108 | 109 | /container/add cmd=/sbin/init hostname=amnezia interface=veth1 logging=yes mounts=awg_config file=docker-awg-arm7.tar 110 | ``` 111 | 112 | To start the container run 113 | 114 | ``` 115 | /container/start 0 116 | ``` 117 | 118 | To get the container shell 119 | 120 | ``` 121 | /container/shell 0 122 | ``` --------------------------------------------------------------------------------