Giter Club home page Giter Club logo

wg-access-server's Introduction

wg-access-server

wg-access-server is a single binary that provides a WireGuard VPN server and device management web ui. We support user authentication, 1 click device registration that works with Mac, Linux, Windows, Ios and Android including QR codes. You can configure different network isolation modes for better control and more.

This project aims to deliver a simple VPN solution for developers, homelab enthusiasts and anyone else feeling adventurous.

wg-access-server is a functional but young project. Contributions are welcome!

Documentation

See our documentation website

Quick Links:

Running with Docker

Here's a quick command to run the server to try it out.

export WG_ADMIN_PASSWORD="example"
export WG_WIREGUARD_PRIVATE_KEY="$(wg genkey)"

docker run \
  -it \
  --rm \
  --cap-add NET_ADMIN \
  --device /dev/net/tun:/dev/net/tun \
  -v wg-access-server-data:/data \
  -e "WG_ADMIN_PASSWORD=$WG_ADMIN_PASSWORD" \
  -e "WG_WIREGUARD_PRIVATE_KEY=$WG_WIREGUARD_PRIVATE_KEY" \
  -p 8000:8000/tcp \
  -p 51820:51820/udp \
  place1/wg-access-server

If you open your browser using your LAN ip address you can even connect your phone to try it out: for example, i'll open my browser at http://192.168.0.XX:8000 using the local LAN IP address.

You can connect to the web server on the local machine browser at http://localhost:8000

Running on Kubernetes via Helm

wg-access-server ships a Helm chart to make it easy to get started on Kubernetes.

Here's a quick start, but you can read more at the Helm Chart Deployment Docs

# deploy
helm install my-release --repo https://place1.github.io/wg-access-server wg-access-server

# cleanup
helm delete my-release

Running with Docker-Compose

Download the the docker-compose.yml file from the repo and run the following command.

export WG_ADMIN_PASSWORD="example"
export WG_WIREGUARD_PRIVATE_KEY="$(wg genkey)"

docker-compose up

You can connect to the web server on the local machine browser at http://localhost:8000

If you open your browser to your machine's LAN IP address you'll be able to connect your phone using the UI and QR code!

Screenshots

Devices

Connect iOS

Connect MacOS

Sign In

Changelog

See the CHANGELOG.md file

Development

The software is made up a Golang Server and React App.

Here's how I develop locally:

  1. run cd website && npm install && npm start to get the frontend running on :3000
  2. run sudo go run ./main.go to get the server running on :8000

Here are some notes about the development configuration:

  • sudo is required because the server uses iptables/ip to configure the VPN networking
  • you'll access the website on :3000 and it'll proxy API requests to :8000 thanks to webpack
  • in-memory storage and generated wireguard keys will be used

GRPC codegeneration:

The client communicates with the server via gRPC-Web. You can edit the API specification in ./proto/*.proto.

After changing a service or message definition you'll want to re-generate server and client code using: ./codegen.sh.

wg-access-server's People

Contributors

antoinebou12 avatar halkeye avatar hongkongkiwi avatar jamescarlos avatar mau04 avatar michael-robbins avatar nfg avatar nqngo avatar place1 avatar sentriz avatar vincentbitter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wg-access-server's Issues

feature request: postgres

This one won't be as detailed as I'm on the phone.

Use case: I don't like persistent volumes in k8s. More things to backup. My postgres instance is already backed up and maintained.

I see there's already storage contracts which is ❤️ , so just add another for postgres

Simplify configuration and improve "getting started" documentation

A big goal of mine is to keep wg-access-server as simple to get started with as possible. I wrote this software in the first place because I always struggled to get OpenVPN and other solutions up and running.

Today wg-access-server is configured with a config file primarily and then some flags/envvars. I'd like to remove the need for a config file entirely and improve the documentation to focus on running the server with environment variables as config.

The 2 primary supported ways to run this software are standalone docker and kubernetes via helm; both of which make configuration via environment variables simple.

I'm planning to follow the general approach that grafana takes: https://grafana.com/docs/grafana/latest/installation/configuration/

In this issue i want to reach out to anyone using wg-access-server for their thoughts on config + documentation.

cc @halkeye @KimchaC

Incorrect generation of server public key

The client key generates to AAA...AA= but after the QR code is gone, the public key is not AAA...AA=.
image

My docker-compose

  wg-access-server:
    image: place1/wg-access-server
    container_name: wg-access-server
    environment:
      - ADMIN_USER=
      - ADMIN_PASSWORD=
    cap_add:
      - NET_ADMIN
    volumes:
      - "./wg-access-server/data:/data"
      - "./wg-access-server/config.yaml:/config.yaml"
    ports:
      - "8000:8000/tcp"
      - "51820:51820/udp"
    devices:
      - "/dev/net/tun:/dev/net/tun"
loglevel: info
disableMetadata: false
port: 8000
storage: "file:///data/"
wireguard:
  interfaceName: wgserver
  privateKey: "<...>="
  externalHost: ""
  port: 51820
vpn:
  cidr: "10.45.0.0/24"
  gatewayInterface: "eno1"
  allowedIPs:
    - "0.0.0.0/0"
dns:
  enabled: true
  upstream:  
    - "1.1.1.1"
auth:
  basic:
    users: ["user:pass"]

[0.2.7-rc7] Duplicate key error

Looks like metadata is trying to save a new device instead of updating an existing device.

wg-access-server-675fd76cc-jlhg4 wg-access-server (/code/internal/storage/sql.go:101)
wg-access-server-675fd76cc-jlhg4 wg-access-server [2020-05-13 16:10:36]  pq: duplicate key value violates unique constraint "key"
wg-access-server-675fd76cc-jlhg4 wg-access-server time="2020-05-13T16:10:36Z" level=debug msg="failed to update device metadata: failed to write device: pq: duplicate key value violates unique constraint \"key\"" file="metadata.go:41"
wg-access-server-675fd76cc-jlhg4 wg-access-server time="2020-05-13T16:10:38Z" level=debug msg="Found devices: [0xc0005af4a0]" file="sql.go:116"
wg-access-server-675fd76cc-jlhg4 wg-access-server time="2020-05-13T16:10:38Z" level=info msg="finished unary call with code OK" file="server_interceptors.go:95" grpc.code=OK grpc.method=ListDevices grpc.service=proto.Devices grpc.start_time="2020-05-13T16:10:38Z" grpc.time_ms=1.452 span.kind=server system=grpc
wg-access-server-675fd76cc-jlhg4 wg-access-server time="2020-05-13T16:10:41Z" level=debug msg="Found devices: [0xc000815080]" file="sql.go:116"
wg-access-server-675fd76cc-jlhg4 wg-access-server time="2020-05-13T16:10:41Z" level=debug msg="saving device d50791ac-dc13-4041-8e4a-15df7756ff17/gavin-phone" file="sql.go:100"

oauth2 with nextcloud

https://docs.nextcloud.com/server/19/developer_manual/client_apis/LoginFlow/index.html#login-flow-v2

I try to configure the oidc (which base on oauth2) against a nextcloud instance.
When I use as issuervalue https://cloud.example.com/index.php/login/v2, I got an error

FATA[0000]oidc.go:39 failed to create oidc provider: oidc: failed to decode provider discovery object: expected Content-Type = application/json, got "text/html; charset=UTF-8": invalid character '<' looking for beginning of value

I'm a bit lost. Or is plain oauth2 not supported? Any chance to support it too?

[docs] Missing gitlab auth guidelines

Hey, first of all, thank you for your project! Opening an issue as TODO doesn't have any points of gitlab auth guidelines/notes/documentation, such as:

  • what type of permission should be granted
  • callback URI(redirectURL)

Only able to access LAN

Setup the container using docker-compose up, no changes to the configuration. Then created a new device, selected iOS and scanned the QR code.

I can then connect and the web interface traffic stats start to go up. When trying to access any webpage, I get a connection time out. Connecting to any of my internal devices (ie. router webpage) seems to work no problem. I'm not sure if having my network on 172.16.x.x has caused some kind of conflict?

I'm not sure what logs I can post to help debug this. If you know of any information I can get that would be useful, i'll be happy to post it.

docker-compose.yml version 3.7 incompatible with Debian 10.6

The current stable version of Debian provides docker-compose version 1.21.0, which complains with:

ERROR: Version in "./docker-compose.yml" is unsupported

Local docker man pages don't give me any indication of the .yml format and version requirements. Is wg-accerss-server using modern docker compose yml file features? Could it possibly be re-worked to support older versions?

Trailing slash required in STORAGE_DIRECTORY

When the environment variable STORAGE_DIRECTORY is set to /data and OpenId is used to login, listing the profiles does not work. New profiles are stored in /data/xxx/yyy.json, but it looks like listing is going wrong. It might looks for /dataxxx/*.json?

p := strings.TrimPrefix(path, s.directory)

If the enviroment variable is set to /data/, everything works fine!

How to use local DNS server?

Let me try and explain my question:

I run wg-access-server and connect with my android phone. inside config.yaml I defined:

dns:
  upstream:
    - "192.168.178.140"

192.168.178.140 is the local IP of the docker host running both adguard home and wg-access-server

I run adguard home as a local filtering DNS and on the first connect from my phone I see this error once. Then never again. Everything works but I think its not using my adguard home as I have checked its query filter.

time="2020-09-11T19:01:12+02:00" level=error msg="failed lookup record with error: read udp 172.29.0.8:52540->192.168.178.140:53: i/o timeout\n;; opcode: QUERY, status: NOERROR, id: 40518\n;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;dns.adguard.com.\tIN\t AAAA\n" file="server.go:89"

wg-access-server is inside

    networks:
      - traefik

as I use traefik for reverse proxy while adguard home runs as
network_mode: bridge
but I am 99% sure that should work. Can anyone spot a problem here?

A docker-free version

Hi,
your software looks so interesting, but I don't like the docker-crap. Is there a way to install it in a normal way?

Docker container keeps crashing and I can't work out why

The error message I'm getting any time I try and launch the container

time="2020-07-17T14:15:28Z" level=info msg="starting wireguard server on 0.0.0.0:51820" file="main.go:50"
panic: runtime error: invalid memory address or nil pointer dereference

[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xa34921]

goroutine 1 [running]:
github.com/place1/wg-embed/pkg/wgembed.(*ConfigFile).Config(...)
/go/pkg/mod/github.com/place1/[email protected]/pkg/wgembed/config.go:152
github.com/place1/wg-embed/pkg/wgembed.(*WireGuardInterface).LoadConfig(0xc000260510, 0xc0001e83c0, 0x4, 0xc000036090)
/go/pkg/mod/github.com/place1/[email protected]/pkg/wgembed/iface.go:92 +0xd1
main.main()
/code/main.go:52 +0x229

Add licence

If planning to make this open-source I suggest adding a LICENCE.md to make this project used by others.

I think this is awesome!!

OIDC throws exception: Invalid memory address or nil pointer dereference

Hi, just updated to the latest version of wg-access-server, but unfortunately OIDC still doesn't work for me. I am trying to connect to keycloak with the following config.yaml:

auth:
  oidc:
    name: "xxx"
    issuer: "https://login.xxx.nl/auth/realms/master"
    clientID: "secure"
    clientSecret: "xxxxxxx-xxx-xxxx-xxxx-xxxxxxxx"
    redirectURL: "https://vpn.xxx.nl"

Version 0.0.9:

  1. Shows wg-access-server screen with 'Sign In: [OIDC]'
  2. Click on OIDC => Redirects to Keycloak and allows to login
  3. Redirects to wg-access-server with 'Sign In: [OIDC]'
  4. Click on OIDC => Redirects to Keycloak and immideately goes back to step 3.

Version 0.1.0:

  1. Shows wg-access-server screen with 'Sign In: [OIDC]'
  2. Click on OIDC => Redirects to Keycloak and allows to login
  3. Throws this exception:
http: panic serving 172.18.0.7:40598: runtime error: invalid memory address or nil pointer dereference
goroutine 186 [running]:
net/http.(*conn).serve.func1(0xc00013b0e0)
	/usr/local/go/src/net/http/server.go:1767 +0x139
panic(0xbb86c0, 0x12e2730)
	/usr/local/go/src/runtime/panic.go:679 +0x1b2
main.main.func2(0x0, 0xc000362fa0, 0xc00051e800)
	/code/main.go:131 +0x2a
github.com/place1/wg-access-server/pkg/authnz.(*AuthMiddleware).Wrap.func4(0xdcd9a0, 0xc0003467e0, 0xc00051e800)
	/code/pkg/authnz/router.go:69 +0x3b2
net/http.HandlerFunc.ServeHTTP(0xc00053e810, 0xdcd9a0, 0xc0003467e0, 0xc00051e800)
	/usr/local/go/src/net/http/server.go:2007 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001a0780, 0xdcd9a0, 0xc0003467e0, 0xc00051e600)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001a0000, 0xdcd9a0, 0xc0003467e0, 0xc00051e400)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
net/http.serverHandler.ServeHTTP(0xc0004680e0, 0xdcd9a0, 0xc0003467e0, 0xc00051e400)
	/usr/local/go/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc00013b0e0, 0xdcf720, 0xc0003ea300)
	/usr/local/go/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
	/usr/local/go/src/net/http/server.go:2928 +0x384

Allow annotations for wg-access-server-web service in Helm

I would like to add some additional annotations to the wg-access-server-web service when installing via helm.

I can add annotations to the wireguard service, but the web service seems to have this field missing.

Could you please add it?

Docker fails to load with error: open /config.yaml: no such file or directory

The :latest tag gives the error;

wg-access-server: error: open /config.yaml: no such file or directory, try --help

and fails to start. The 0.2.5 tag works fine. My docker-compose file is;

  wg-access-server:
    image: place1/wg-access-server:latest
    container_name: wg-access-server
    restart: unless-stopped
    networks:
      - t2_proxy
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    ports:
      # - "$WIREGUARD_PORT:8000/tcp"
      - "$WIREGUARD_UDP_PORT:51820/udp"
    volumes:
      - $CONFIG/wg-access-server/data:/data
      # - $CONFIG/wg-access-server/config.yaml:/config.yaml # if you have a custom config file
    environment:
      WIREGUARD_PRIVATE_KEY: $WIREGUARD_PRIVATE_KEY
      ADMIN_USERNAME: $WIREGUARD_ADMIN_USERNAME
      ADMIN_PASSWORD: $WIREGUARD_ADMIN_PASSWORD
      LOG_LEVEL: debug
    devices:
      - /dev/net/tun
    labels:
      - "traefik.enable=true"
      ## HTTP Routers
      - "traefik.http.routers.wireguard-as-rtr.entrypoints=https"
      - "traefik.http.routers.wireguard-as-rtr.rule=Host(`vpn.$DOMAINNAME`)"
      ## Middlewares
      - "traefik.http.routers.wireguard-as-rtr.middlewares=chain-authelia@file"
      ## HTTP Services
      - "traefik.http.routers.wireguard-as-rtr.service=wireguard-as-svc"
      - "traefik.http.services.wireguard-as-svc.loadbalancer.server.port=8000"

Feature Request: OIDC support for admin

First off, I'm loving this. I was able to get wireguard working in k8s super quickly, with just a few helm file tweaks, which I've submitted as PR.

I'm using keycloak for auth, using the oidc setup, but now I want to get admin access working. I see for htaccess you setup user.Claims.Add("admin", "true") which shouldn't be that hard to reproduce for oidc, I just don't know enough about it for oidc to do it in a standard way.

I can get keycloak to return a list of client id scoped roles, or system wide roles, or groups for a user. All i'm pretty sure are keycloak specific options. I can get it returning in any field I want.

I don't mind writing the code, I just need suggestions/feedback on what is needed.

I'm thinking maybe the config needs another 2 fields.
claimsField which field the oidc returns the claims in
adminClaim which value constitutes being an admin?

So for me I could do:

claimsField: "groups"
adminClaim: "wireguard-admin"

Does that make sense?

Android can re-use the iOS QR Code

TODO: I don't have an android phone :(

I can confirm that Wireguard on android can use the same QR code as iOS.

Steps taken

  1. Install wg-access-server
  2. Add a new device, but use the iOS QR Code and instructions with the Wireguard Android app
  3. Have a working Wireguard connection

I don't have time to dive into React and make this (I think trivial change) myself; but it should be easy enough to add the same QR code and instructions to the Android tab. Just wanted to let you know I tested this - and it works.

A bit of marketing... :)

I think you can tell I am super excited about this project of your's... But I stumbled upon it completely by accident and it wasn't showing up in my google searches.

I think most people would search for something like:

  • wireguard UI
  • wireguard GUI
  • wireguard web interface

But you barely mention these words in your read me. I think you could drastically increase the visibility of your project by...

  • Changing the readme title to the words "WG-Access-Server: Advanced Wireguard UI and Web Interface"
  • Move screenshots up below documentation
  • Changing the first paragraph to highlight the standout features
wg-access-server is a single binary that provides a WireGuard VPN server and device management web ui. 

Features
- Multi-user authentication through OIDC and gitlab
- 1-click device registration that works with Mac, Linux, Windows, iOS and Android 
- QR code support for iOS and Android 
- Different network isolation modes that "just work" without messing with iptables and NAT

That should make it more likely to appear in the google search results for relevant terms.

And then you could also promote it a little. If you google "wireguard ui" you will see all the other UI developers posted about it on reddit on /r/WireGuard/ and /r/WireGuard/.

That could of course wait a little if you are planning on making a lot of improvements in the near future, but I think your project is already good to go!

I would also be more than happy to help sharing it.

Allow admin to delete devices of other users

It would be great if an admin could remove devices from the /admin/all-devices page so companies using wg-access-server can remove users' vpn access easily. Currently an admin can only remove his own devices like any regular user.

Add support for PostUp

I'd like to add some iptables rules after the wg0 interface for the wg-access-server comes up. Supporting a PostUp config option similiar to wg-quick seems like the most straight forward way to achieve that.

404 error on page refresh for /admin/all-devices

When logged in as admin and viewing /admin/all-devices, a page refresh will result in a 404 error.

PS: the "auth provider" on the all-devices page seems to be empty for users who used Gitlab auth.

Use email as the owner

Hi,

First of all I want to thank you for this phenomenal project. You have done an amazing job.

I have a small feature request: When using OIDC (google), can you show the user's email as the owner instead of the token?

The reason is that it's impossible to actually tie the token to an actual user in case access needs to be revoked.

Thanks, Kim

Allow adjustment of AllowedIPs and removal of DNS

Hi,

I have another feature request.

Feature request

I am using wireguard to connect to our internal company network. So only company internal traffic should go through the VPN.

Can you please make AllowedIPs customizable from the config?

And the same goes for DNS. When connected through the VPN I don't want DNS to go through the VPN so it would be great if that could be disabled completely.

Workaround

For anyone else who is looking for this functionality in the meantime, I have figured out a workaround.

  • Copy the file /website/build/static/js/main.086d0b42.chunk.js from the container
  • Adjust the AllowedIPs part inside of it
  • Comment out the DNS section with a "#". Don't remove it as it will mess up the dynamic parameters
  • Add this to your docker-compose volumes section - "./patch/main.086d0b42.chunk.js:/website/build/static/js/main.086d0b42.chunk.js:rw"
  • Restart the container

This will replace main.086d0b42.chunk.js with your customized version and cause the frontend to generate wireguard configs with your desired options.

radius/NPS support

Since Active Directory can provide radius support through NPS role we can:

  1. Auth to web management with NPS for certain groups in NPS
  2. Add VPN peers with username provided by NPS, like 2FA - adding at web for ex. for user "j.smith", wg-access-server asks for possibility to add this user to VPN peers, and if user have such permissions - add peer with this username\comment. Also - check by cron if user doesn't have permissions to vpn then wg-access-server deletes peer from userlist.

how about such implementations? that would be usefull for companies with AD (50+ users).

Cannot reconnect after container restart

Hi,

First of all, thanks for this great project! I really appreciate how accessible it makes Wireguard.

  • I am using Portainer + Docker to deploy wg-access-server.
  • I fail to reconnect (from my iPhone) after the container has been restarted using an existing config.
  • If I generate a new config (i.e. add a new device) after the container has been restarted, that works perfectly well! So I cannot reconnect using a config that has been added before the restart.
  • It might be worth noting that I don't have the same issue with linuxserver/wireguard

What might be the cause of this?

Thanks!

iOS Client Logs

2020-08-05 11:17:37.094048: [APP] startActivation: Entering (tunnel: bora iphone) 
2020-08-05 11:17:37.094809: [APP] startActivation: Tunnel is disabled. Re-enabling and saving 
2020-08-05 11:17:37.132817: [APP] startActivation: Tunnel saved after re-enabling, invoking startActivation 
2020-08-05 11:17:37.133229: [APP] startActivation: Entering (tunnel: bora iphone) 
2020-08-05 11:17:37.133628: [APP] startActivation: Starting tunnel 
2020-08-05 11:17:37.133977: [APP] startActivation: Success 
2020-08-05 11:17:37.147014: [APP] Tunnel 'bora iphone' connection status changed to 'connecting' 
2020-08-05 11:17:37.206130: [NET] App version: 0.0.20200127 (17); Go backend version: 0.0.20200121 
2020-08-05 11:17:37.206231: [NET] Starting tunnel from the app 
2020-08-05 11:17:38.046469: [NET] Tunnel interface is utun2 
2020-08-05 11:17:38.047455: [NET] DNS64: mapped xxx.xx.xxx.xxx to itself. 
2020-08-05 11:17:38.048100: [NET] Attaching to interface 
2020-08-05 11:17:38.049407: [NET] Routine: encryption worker - started 
2020-08-05 11:17:38.049547: [NET] Routine: encryption worker - started 
2020-08-05 11:17:38.049633: [NET] Routine: handshake worker - started 
2020-08-05 11:17:38.049722: [NET] Routine: decryption worker - started 
2020-08-05 11:17:38.049810: [NET] Routine: decryption worker - started 
2020-08-05 11:17:38.049894: [NET] Routine: handshake worker - started 
2020-08-05 11:17:38.049986: [NET] Routine: encryption worker - started 
2020-08-05 11:17:38.050074: [NET] Routine: decryption worker - started 
2020-08-05 11:17:38.050164: [NET] Routine: handshake worker - started 
2020-08-05 11:17:38.050262: [NET] Routine: encryption worker - started 
2020-08-05 11:17:38.050356: [NET] Routine: handshake worker - started 
2020-08-05 11:17:38.050444: [NET] Routine: handshake worker - started 
2020-08-05 11:17:38.050542: [NET] Routine: encryption worker - started 
2020-08-05 11:17:38.050628: [NET] Routine: decryption worker - started 
2020-08-05 11:17:38.050720: [NET] Routine: decryption worker - started 
2020-08-05 11:17:38.050824: [NET] Routine: encryption worker - started 
2020-08-05 11:17:38.051070: [NET] Routine: handshake worker - started 
2020-08-05 11:17:38.051160: [NET] Routine: TUN reader - started 
2020-08-05 11:17:38.051283: [NET] Routine: event worker - started 
2020-08-05 11:17:38.051347: [NET] Routine: decryption worker - started 
2020-08-05 11:17:38.051553: [NET] UAPI: Updating private key 
2020-08-05 11:17:38.052191: [NET] UAPI: Removing all peers 
2020-08-05 11:17:38.052252: [NET] UAPI: Transition to peer configuration 
2020-08-05 11:17:38.053027: [NET] peer(Sca5…Ka2o) - UAPI: Created 
2020-08-05 11:17:38.053111: [NET] peer(Sca5…Ka2o) - UAPI: Updating endpoint 
2020-08-05 11:17:38.053253: [NET] peer(Sca5…Ka2o) - UAPI: Updating persistent keepalive interval 
2020-08-05 11:17:38.053392: [NET] peer(Sca5…Ka2o) - UAPI: Removing all allowedips 
2020-08-05 11:17:38.053488: [NET] peer(Sca5…Ka2o) - UAPI: Adding allowedip 
2020-08-05 11:17:38.054832: [NET] Routine: receive incoming IPv6 - started 
2020-08-05 11:17:38.054926: [NET] Routine: receive incoming IPv4 - started 
2020-08-05 11:17:38.055028: [NET] UDP bind has been updated 
2020-08-05 11:17:38.055181: [NET] peer(Sca5…Ka2o) - Starting... 
2020-08-05 11:17:38.055504: [NET] peer(Sca5…Ka2o) - Routine: sequential receiver - started 
2020-08-05 11:17:38.055577: [NET] peer(Sca5…Ka2o) - Routine: nonce worker - started 
2020-08-05 11:17:38.055683: [NET] peer(Sca5…Ka2o) - Routine: sequential sender - started 
2020-08-05 11:17:38.055795: [NET] Device started 
2020-08-05 11:17:38.057582: [APP] Tunnel 'bora iphone' connection status changed to 'connected' 
2020-08-05 11:17:38.299137: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:17:38.303860: [NET] peer(Sca5…Ka2o) - Awaiting keypair 
2020-08-05 11:17:43.578353: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:17:43.578739: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:17:48.746734: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:17:48.747139: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:17:54.038063: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:17:54.038424: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:17:59.225477: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:17:59.225827: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:04.486562: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 3) 
2020-08-05 11:18:04.486949: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:08.979962: [APP] Status update notification timeout for tunnel 'bora iphone'. Tunnel status is now 'connected'. 
2020-08-05 11:18:09.820787: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:18:09.820985: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:14.906744: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:18:14.907174: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:20.218583: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 3) 
2020-08-05 11:18:20.218751: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:25.364612: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:18:25.364954: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:30.513666: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:18:30.514041: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:35.771506: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:41.044322: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:18:41.044723: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:46.130522: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:18:46.130913: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:51.245644: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:18:51.246033: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:18:56.325986: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:18:56.326288: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:19:01.375373: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:19:06.398608: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:19:06.398926: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:19:11.499492: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:19:11.499851: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:19:16.588785: [NET] peer(Sca5…Ka2o) - Handshake did not complete after 5 seconds, retrying (try 2) 
2020-08-05 11:19:16.589149: [NET] peer(Sca5…Ka2o) - Sending handshake initiation 
2020-08-05 11:19:20.896704: [APP] startDeactivation: Tunnel: bora iphone 
2020-08-05 11:19:20.903566: [APP] Tunnel 'bora iphone' connection status changed to 'disconnecting' 
2020-08-05 11:19:21.155563: [NET] Network change detected with satisfied route and interface order [en0] 
2020-08-05 11:19:21.158278: [NET] DNS64: mapped xxx.xx.xxx.xxx to itself. 
2020-08-05 11:19:21.158766: [NET] UAPI: Transition to peer configuration 
2020-08-05 11:19:21.159076: [NET] peer(Sca5…Ka2o) - UAPI: Updating endpoint 
2020-08-05 11:19:21.161552: [NET] Routine: receive incoming IPv4 - stopped 
2020-08-05 11:19:21.169471: [NET] Routine: receive incoming IPv6 - stopped 
2020-08-05 11:19:21.170954: [NET] Routine: receive incoming IPv4 - started 
2020-08-05 11:19:21.171179: [NET] Routine: receive incoming IPv6 - started 
2020-08-05 11:19:21.171788: [NET] UDP bind has been updated 
2020-08-05 11:19:21.222858: [NET] Stopping tunnel 
2020-08-05 11:19:21.223364: [NET] Device closing 
2020-08-05 11:19:21.224009: [NET] Routine: event worker - stopped 
2020-08-05 11:19:21.225276: [NET] Routine: TUN reader - stopped 
2020-08-05 11:19:21.225847: [NET] Routine: receive incoming IPv4 - stopped 
2020-08-05 11:19:21.226124: [NET] Routine: receive incoming IPv6 - stopped 
2020-08-05 11:19:21.226504: [NET] peer(Sca5…Ka2o) - Stopping... 
2020-08-05 11:19:21.226791: [NET] Routine: encryption worker - stopped 
2020-08-05 11:19:21.226986: [NET] Routine: decryption worker - stopped 
2020-08-05 11:19:21.227168: [NET] Routine: handshake worker - stopped 
2020-08-05 11:19:21.227344: [NET] Routine: encryption worker - stopped 
2020-08-05 11:19:21.227513: [NET] Routine: decryption worker - stopped 
2020-08-05 11:19:21.227677: [NET] Routine: decryption worker - stopped 
2020-08-05 11:19:21.227965: [NET] Routine: encryption worker - stopped 
2020-08-05 11:19:21.228215: [NET] Routine: handshake worker - stopped 
2020-08-05 11:19:21.228446: [NET] Routine: handshake worker - stopped 
2020-08-05 11:19:21.228631: [NET] Routine: handshake worker - stopped 
2020-08-05 11:19:21.228827: [NET] Routine: handshake worker - stopped 
2020-08-05 11:19:21.229007: [NET] Routine: decryption worker - stopped 
2020-08-05 11:19:21.229191: [NET] Routine: encryption worker - stopped 
2020-08-05 11:19:21.229372: [NET] Routine: decryption worker - stopped 
2020-08-05 11:19:21.229552: [NET] Routine: decryption worker - stopped 
2020-08-05 11:19:21.229731: [NET] Routine: handshake worker - stopped 
2020-08-05 11:19:21.229908: [NET] Routine: encryption worker - stopped 
2020-08-05 11:19:21.230081: [NET] Routine: encryption worker - stopped 
2020-08-05 11:19:21.230310: [NET] peer(Sca5…Ka2o) - Routine: nonce worker - stopped 
2020-08-05 11:19:21.230553: [NET] peer(Sca5…Ka2o) - Routine: sequential sender - stopped 
2020-08-05 11:19:21.230795: [NET] peer(Sca5…Ka2o) - Routine: sequential receiver - stopped 
2020-08-05 11:19:21.231233: [NET] Interface closed 
2020-08-05 11:19:21.240522: [APP] Tunnel 'bora iphone' connection status changed to 'disconnected'

docker-compose.yaml

version: 2
services:
  wg-access-server:
    image: place1/wg-access-server
    container_name: wg-access-server
    cap_add:
      - NET_ADMIN
    volumes:
      - "wg-access-server-data:/data"
    ports:
      - "51820:51820/udp"
    devices:
      - "/dev/net/tun:/dev/net/tun"
    networks:
      - public_bridge  # for reverse proxy

volumes:
  wg-access-server-data:
    driver: local

networks:
  public_bridge:
    external:
      name: public_bridge

Allow changing server ports

Another (low priority) feature request... I don't mean to overwhelm you with all of it or seem entitled. It just seems you are really motivated to make this a great project and I want to contribute from a user's perspective.

It would be great if we could adjust the web interface port from the config. For example, I had to run the server in network_mode=host where the server binds to the port on the host container instead of the docker container and had something else running on port 8000.

I had to change the port on my other existing service and all dependencies for it. It would be great if we could adjust that from the config.

Support multiple gateway interfaces

Currently one can specify a single gateway interface to route the traffic through.

My server has two interfaces: eth0 for general internet and ens10 for lan. I would like to be able to route 10.0.0.0/8 through ens10 and everything else through eth0. Currently wg-access-server only lets me route everything through either eth0 (can't access lan) or ens10 (can't access the internet).

Maybe the gatewayInterface config option could be turned into a map so one can specify CIDR->interface pairs?

API for adding/removing devices and downloading config

Hi there,

I plan to add wireguard to many servers and have the devices managed by wg-access-server.

It would be really great to have a REST API so I can automate several tasks via bash.

Here's an example flow:

  • Server is setup
  • Wireguard device added from new server using API
  • Wireguard client config downloaded from server using API

sqlite Error

failed to connect/open storage backend: failed to connect to sqlite3: Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub" file="main.go:77"

Forwarding not working

Today I set up a fresh VM and installed wg-access-server on it. To my surprise it didn't work out of the box unlike my other server.

I think the reason is that on my old server I was adding forwarding config myself.

Relevant wg-access-server config parts:

vpn:
  cidr: "172.21.0.0/16"

  rules:
    allowVPNLAN: true
    allowServerLAN: false
    allowInternet: true
    allowedNetworks:
      - 10.120.0.0/13 
      - 40.71.XX.XX/32 # Servers external IP

Out of the box after the start of wg-access-server my iptables looked like this...

-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
-N DOCKER-USER
-N WG_ACCESS_SERVER_FORWARD
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o br-95062ea5c319 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-95062ea5c319 -j DOCKER
-A FORWARD -i br-95062ea5c319 ! -o br-95062ea5c319 -j ACCEPT
-A FORWARD -i br-95062ea5c319 -o br-95062ea5c319 -j ACCEPT
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A FORWARD -j WG_ACCESS_SERVER_FORWARD
-A DOCKER -d 172.18.0.3/32 ! -i br-95062ea5c319 -o br-95062ea5c319 -p tcp -m tcp --dport 443 -j ACCEPT
-A DOCKER -d 172.18.0.3/32 ! -i br-95062ea5c319 -o br-95062ea5c319 -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-95062ea5c319 ! -o br-95062ea5c319 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o br-95062ea5c319 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 10.120.0.0/13 -j ACCEPT
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 40.71.XX.XX/32 -j ACCEPT
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 172.21.0.0/16 -j ACCEPT
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 10.0.0.0/8 -j REJECT --reject-with icmp-port-unreachable
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 172.16.0.0/12 -j REJECT --reject-with icmp-port-unreachable
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 192.168.0.0/16 -j REJECT --reject-with icmp-port-unreachable
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -i eth0 -o wg1 -j ACCEPT
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -i wg1 -o eth0 -j ACCEPT

Ping and connections to 40.71.XX.XX were failing.

Executing...

sudo iptables -A WG_ACCESS_SERVER_FORWARD -o wg1 -j ACCEPT

Seemed to be enough to fix it. I don't really understand all the iptables rules, but most wireguard configs I looked at execute both -i wg1 and -o wg1. So I did both and removed the original -i/-o rules:

sudo iptables -A WG_ACCESS_SERVER_FORWARD -o wg1 -j ACCEPT
sudo iptables -A WG_ACCESS_SERVER_FORWARD -i wg1 -j ACCEPT
sudo iptables -D WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -i eth0 -o wg1 -j ACCEPT
sudo iptables -D WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -i wg1 -o eth0 -j ACCEPT

For a final config of:

$ sudo iptables -S
-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
-N DOCKER-USER
-N WG_ACCESS_SERVER_FORWARD
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o br-95062ea5c319 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-95062ea5c319 -j DOCKER
-A FORWARD -i br-95062ea5c319 ! -o br-95062ea5c319 -j ACCEPT
-A FORWARD -i br-95062ea5c319 -o br-95062ea5c319 -j ACCEPT
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A FORWARD -j WG_ACCESS_SERVER_FORWARD
-A DOCKER -d 172.18.0.3/32 ! -i br-95062ea5c319 -o br-95062ea5c319 -p tcp -m tcp --dport 443 -j ACCEPT
-A DOCKER -d 172.18.0.3/32 ! -i br-95062ea5c319 -o br-95062ea5c319 -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-95062ea5c319 ! -o br-95062ea5c319 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o br-95062ea5c319 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 10.120.0.0/13 -j ACCEPT
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 40.71.XX.XX/32 -j ACCEPT
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 172.21.0.0/16 -j ACCEPT
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 10.0.0.0/8 -j REJECT --reject-with icmp-port-unreachable
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 172.16.0.0/12 -j REJECT --reject-with icmp-port-unreachable
-A WG_ACCESS_SERVER_FORWARD -s 172.21.0.0/16 -d 192.168.0.0/16 -j REJECT --reject-with icmp-port-unreachable
-A WG_ACCESS_SERVER_FORWARD -o wg1 -j ACCEPT
-A WG_ACCESS_SERVER_FORWARD -i wg1 -j ACCEPT

This worked for me.

But of course the chain is cleaned on each restart. So until it is fixed I am using this for now:

sudo iptables -A FORWARD -o wg1 -j ACCEPT
sudo iptables -A FORWARD -i wg1 -j ACCEPT

After that I tried setting allowInternet: false and expected it to continue working, but it didn't. Took me forever to debug, but the missing rule was:

sudo iptables -t nat -A WG_ACCESS_SERVER_POSTROUTING -s 172.21.0.0/16 -o eth0 -j MASQUERADE

After that everything seems to be working as expected.

So...

		if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", cidr, "-i", gatewayIface, "-o", wgIface, "-j", "ACCEPT"); err != nil {
			return errors.Wrap(err, "failed to set ip tables rule")
		}
		if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", cidr, "-i", wgIface, "-o", gatewayIface, "-j", "ACCEPT"); err != nil {
			return errors.Wrap(err, "failed to set ip tables rule")
		}
		if err := ipt.AppendUnique("nat", "WG_ACCESS_SERVER_POSTROUTING", "-s", cidr, "-o", gatewayIface, "-j", "MASQUERADE"); err != nil {
			return errors.Wrap(err, "failed to set ip tables rule")
		}

Should be enabled regardless of whether AllowInternet is on and the filter rules need to be changed to only have one interface.

And then it should all work. If AllowInternet is false, then the REJECT rule should take care of the blocking (it worked in my case).

QR code broken in Firefox

Using current FF 78.0.1 under OSX, the QR code image seems to be broken. See attached screenshot. It worked fine in Safari.

Screen Shot 2020-07-07 at 17 55 57

How to avoid wireguard docker NAT and masquerading issues

This is not really a feature request, but something I struggled with and I think other people may too. So I wanted to document the solution here and it can be closed right away.

By default docker places containers (including wg-access-server) in it's own network like 172.28.0.0/16 and then uses NAT and masquerading to route the traffic into the internal network.

Let's say the wg-access-server container has the IP 172.28.0.8. All traffic coming from it to the host's network will seem to come from the docker0 IP 172.28.0.1.

What it means for wg-access-server is that all connections from the VPN clients will also appear to come from 172.28.0.1 instead of from their VPN IP (like 10.44.0.3).

You can test this by running nc -kvl 5060 on one of the servers in the host network and then connecting from a VPN client to it using telnet 5060. It will show 172.28.0.1 as the originator.

The only way I could find to solve this issue was by running the container in network-mode: host.

I did this by adding this to my docker-compose.yml:

version: "3.7"
services:
  wg-access-server:
    [...]
    network_mode: "host"

If you already have a wireguard interface on the host you also need to change the interface in the config.yaml:

wireguard:
  # The network interface name for wireguard
  # Optional
  interfaceName: wg1

After making that change connections from VPN clients come from their IPs in the VPN network.

I am using traefik as my reverse proxy in front of docker services and this made it impossible to use the automatic discovery. So I added a file provider with the following config:

# Traefik can't route to containers running in host network mode.
# So we use this config to define it.

http:
  routers:
    vpn:
      service: vpn_service
      rule: "Host(`vpn.example.com`)"

  services:
    vpn_service:
      loadBalancer:
        servers:
          - url: http://172.17.0.1:8000

Another thing that was particular to my own setup is that I am running internal services on the same host. I wanted them to be accessible from both the internet and from the VPN. When access from the VPN they should either request a login or show a "Connect to VPN to access message". And when accessed from within the VPN they should be allowed without an additional login.

I was able to achieve this by adding the server's external IP to my wireguard AllowedIPs config, such as:

AllowedIPs = 10.44.0.0/16, 10.0.0.0/16, 35.233.XX.XX/32

But since now all connections to 35.233.XX.XX were routed through the internet of the VPN server all the logs showed that the traffic came also from the external IP 35.233.XX.XX (VPN and services are on the same server in my case).

I was able to solve this by changing requests to that IP to the IP of the traefik container:

sudo iptables -t nat -A PREROUTING -p tcp -d 35.233.XX.XX --dport 443 -i wg1 -j DNAT --to 172.28.0.6:443

Now when a VPN client tries to connect to service.example.com:443 their request is redirected from 35.233.XX.XX:443 to 172.28.0.6:443 and the logs show the connection coming from the user's VPN IP (like 10.44.0.3).

Hopefully this can save someone some time.

Ability to print out OIDC tokens with Debug logging

Currently it's super hard to figure out what my OIDC token contains and how that maps to roles the user is in.

It would be great to have a CLI flag that enables the server to print out the tokens to allow users to debug the exact path they need to specify in the userClaimsRules

Small UI adjustments

A few more super low priority things I have noticed...

1. Button order on add screen

When you add a new config on the download screen it says

  1. Install WireGuard for MacOS
  2. Download your connection file
  3. Add tunnel from file

But the buttons show:

  • Download VPN Config
  • Download wireguard

2. Linux screen without instructions

The linux screen just shows 1. hmmm todo instead of the steps like the other OS

3. No app links for iOS and Android

Since iOS and Android show the QR code, I think you could just make the WireGuard app text in the instructions on the left a link to the app stores.

4. Customize OIDC button

The config OIDC section as a name variable, but it doesn't seem to be used anywhere. I think it would be great to replace the OIDC button text with that value.

[0.2.0-rc7] Bad Address

My config has:

    vpn:
      rules:
        allowedNetworks:
          - 0.0.0.0/0
          - 128.0.0.0/0
          - ::/0
          - 172.16.10.0/24

And it seems to generate a config

AllowedIPs = 10.44.0.1/32, 10.44.0.0/24, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 200.0.0.0/5, 172.64.0.0/10, 172.128.0.0/9, 12.0.0.0/6, 16.0.0.0/4, 11.0.0.0/8, 32.0.0.0/3, 128.0.0.0/3, 196.0.0.0/6, 64.0.0.0/2, 172.0.0.0/12, 194.0.0.0/7, 192.160.0.0/13, 192.0.0.0/9, 192.170.0.0/15, 160.0.0.0/5, 192.128.0.0/11, 193.0.0.0/8, 208.0.0.0/4, 192.172.0.0/14, 176.0.0.0/4, 192.169.0.0/16, 0.0.0.0/5, 174.0.0.0/7, 192.176.0.0/12, 192.192.0.0/10, 8.0.0.0/7, 172.32.0.0/11, 173.0.0.0/8, 168.0.0.0/6, 0.0.0.0/0, 128.0.0.0/0, ::/0, 172.16.10.0/24

Which wireguard for android goes "Error bringing up tunnel: Bad Address"

I havn't tracked it down to the actual cause though

Support for ARM devices

Hey,
Docker image is not supported on ARM based devices. Are you planning to support those devices?

Gitlab auth not working due to email verification failure

I've configured Gitlab auth, am seeing the button to login via Gitlab in the UI, get to my Gitlab instance and grant access, get redirected to /auth/callback where I see the following message:

oidc: get access token: oauth2: token expired and refresh token is not set

Additionally I see the below panic in the logs which suggests it's a problem with verifying the email domain. When I remove the domain from the emailDomains config option, the auth starts working. Maybe wg-access-server does not get my email from Gitlab correctly. I guess it's trying to access parsed[1] on an empty string split.

2020/07/02 22:30:38 http: panic serving 171.6.x.x:49455: runtime error: index out of range [1] with length 1
goroutine 74 [running]:
net/http.(*conn).serve.func1(0xc000340aa0)
	/usr/local/go/src/net/http/server.go:1767 +0x139
panic(0xd2e780, 0xc0003bd460)
	/usr/local/go/src/runtime/panic.go:679 +0x1b2
github.com/place1/wg-access-server/pkg/authnz/authconfig.verifyEmailDomain(0xc0001d3c50, 0x1, 0x1, 0x0, 0x0, 0xc00010e500)
	/code/pkg/authnz/authconfig/oidc.go:149 +0x146
github.com/place1/wg-access-server/pkg/authnz/authconfig.(*OIDCConfig).callbackHandler.func1(0xeddbc0, 0xc0002280e0, 0xc000178400)
	/code/pkg/authnz/authconfig/oidc.go:104 +0x31f
net/http.HandlerFunc.ServeHTTP(0xc0005631d0, 0xeddbc0, 0xc0002280e0, 0xc000178400)
	/usr/local/go/src/net/http/server.go:2007 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0000cc3c0, 0xeddbc0, 0xc0002280e0, 0xc000178200)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0000cc000, 0xeddbc0, 0xc0002280e0, 0xc000179f00)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
net/http.serverHandler.ServeHTTP(0xc000494b60, 0xeddbc0, 0xc0002280e0, 0xc000179f00)
	/usr/local/go/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc000340aa0, 0xedfec0, 0xc0001dd600)
	/usr/local/go/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
	/usr/local/go/src/net/http/server.go:2928 +0x384
2020/07/02 22:31:54 http: panic serving 171.6.240.128:49460: runtime error: index out of range [1] with length 1
goroutine 107 [running]:
net/http.(*conn).serve.func1(0xc000159180)
	/usr/local/go/src/net/http/server.go:1767 +0x139
panic(0xd2e780, 0xc00041d100)
	/usr/local/go/src/runtime/panic.go:679 +0x1b2
github.com/place1/wg-access-server/pkg/authnz/authconfig.verifyEmailDomain(0xc0001d3c50, 0x1, 0x1, 0x0, 0x0, 0xc00010e370)
	/code/pkg/authnz/authconfig/oidc.go:149 +0x146
github.com/place1/wg-access-server/pkg/authnz/authconfig.(*OIDCConfig).callbackHandler.func1(0xeddbc0, 0xc0002281c0, 0xc000178800)
	/code/pkg/authnz/authconfig/oidc.go:104 +0x31f
net/http.HandlerFunc.ServeHTTP(0xc0005631d0, 0xeddbc0, 0xc0002281c0, 0xc000178800)
	/usr/local/go/src/net/http/server.go:2007 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0000cc3c0, 0xeddbc0, 0xc0002281c0, 0xc000178600)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0000cc000, 0xeddbc0, 0xc0002281c0, 0xc000178400)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
net/http.serverHandler.ServeHTTP(0xc000494b60, 0xeddbc0, 0xc0002281c0, 0xc000178400)
	/usr/local/go/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc000159180, 0xedfec0, 0xc000460740)
	/usr/local/go/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
	/usr/local/go/src/net/http/server.go:2928 +0x384

bad nonce error on oidc login flow

While using the OIDC login flow on the first login attempt from a clean tab I get the error "bad nonce".
image
Going back to https://myserver.mydomain.com/signin allows me to try again and the second time it works.

From looking at my traffic with an intercept proxy I was able to confirm my state (nonce) looks the same throughout the sign on flow and that the urls of the successful flows look the same as the "bad nonce" ones up to when the "bad nonce" comes back from the server.

The message seems to originate from here:

http.Error(w, "bad nonce", http.StatusBadRequest)

I thought it might have been timeout related to this value:

ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)

But my attempts to fix this by increasing the timeout were unsuccessful, changes: verdin@34872ba Even after making these changes I was still getting the "bad nonce" error. Although the server log "runtime error: invalid memory " error seemed to be gone, or less common.

My OIDC provider is AWS Cognito.

I am interested in digging into this but don't really know where to look next. I am also happy to run any tests or pull any logs that would be helpful.

Server log error, happens when I get "bad nonce"

time="2020-04-26T08:11:17Z" level=info msg="finished unary call with code OK" file="server_interceptors.go:95" grpc.code=OK grpc.method=ListDevices grpc.service=proto.Devices grpc.start_time="2020-04-26T08:11:17Z" grpc.time_ms=0.755 span.kind=server system=grpc
2020/04/26 23:14:06 http: panic serving 10.0.10.16:58098: runtime error: invalid memory address or nil pointer dereference
goroutine 333170 [running]:
net/http.(*conn).serve.func1(0xc000568320)
        /usr/local/go/src/net/http/server.go:1767 +0x139
panic(0xbb9960, 0x12e57b0)
        /usr/local/go/src/runtime/panic.go:679 +0x1b2
main.main.func2(0x0, 0xc0002ad440, 0xc000114900)
        /code/main.go:140 +0x2a
github.com/place1/wg-access-server/pkg/authnz.(*AuthMiddleware).Wrap.func4(0xdcf5c0, 0xc000566000, 0xc000114900)
        /code/pkg/authnz/router.go:69 +0x3b2
net/http.HandlerFunc.ServeHTTP(0xc000507f80, 0xdcf5c0, 0xc000566000, 0xc000114900)
        /usr/local/go/src/net/http/server.go:2007 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc000162900, 0xdcf5c0, 0xc000566000, 0xc000114700)
        /go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
github.com/gorilla/mux.(*Router).ServeHTTP(0xc000162000, 0xdcf5c0, 0xc000566000, 0xc000114500)
        /go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
net/http.serverHandler.ServeHTTP(0xc0005660e0, 0xdcf5c0, 0xc000566000, 0xc000114500)
        /usr/local/go/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc000568320, 0xdd1340, 0xc0006aca40)
        /usr/local/go/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384
2020/04/26 23:14:30 http: panic serving 10.0.10.16:58100: runtime error: invalid memory address or nil pointer dereference
goroutine 333182 [running]:
net/http.(*conn).serve.func1(0xc000569900)
        /usr/local/go/src/net/http/server.go:1767 +0x139
panic(0xbb9960, 0x12e57b0)
        /usr/local/go/src/runtime/panic.go:679 +0x1b2
main.main.func2(0x0, 0xc0002ad440, 0xc000115400)
        /code/main.go:140 +0x2a
github.com/place1/wg-access-server/pkg/authnz.(*AuthMiddleware).Wrap.func4(0xdcf5c0, 0xc0005662a0, 0xc000115400)
        /code/pkg/authnz/router.go:69 +0x3b2
net/http.HandlerFunc.ServeHTTP(0xc000507f80, 0xdcf5c0, 0xc0005662a0, 0xc000115400)
        /usr/local/go/src/net/http/server.go:2007 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc000162900, 0xdcf5c0, 0xc0005662a0, 0xc000115200)
        /go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
github.com/gorilla/mux.(*Router).ServeHTTP(0xc000162000, 0xdcf5c0, 0xc0005662a0, 0xc000114f00)
        /go/pkg/mod/github.com/gorilla/[email protected]/mux.go:210 +0xe2
net/http.serverHandler.ServeHTTP(0xc0005660e0, 0xdcf5c0, 0xc0005662a0, 0xc000114f00)
        /usr/local/go/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc000569900, 0xdd1340, 0xc000302880)
        /usr/local/go/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384

My OIDC in config.yaml

 oidc:
    name: "AWSCognito" # anything you want
    issuer: "https://cognito-idp.us-west-2.amazonaws.com/us-west-[...]" # Should point to the oidc url without .well-known
    clientID: "j[...]f"
    clientSecret: "p9[...]4"
    scopes: ["openid"]  # list of scopes, defaults to ["openid"]
    redirectURL: "https://[...].[...].[...].com/auth/callback" # full url you want the oidc to redirect to, example: https://vpn-admin.example.com/finish-signin
    # Optionally restrict login to users with an allowed email domain
    # if empty or omitted, any email domain will be allowed.
#    emailDomains:
#      - example.com

Improve client connection status display

The web ui will show clients as disconnected if the last handshake was more than 1 minute ago.

As far as I can tell wireguard will only establish a new handshake if the current one is more than 120s ago and only when data is sent. If no data is transferred no new handshake will be established.

This results in clients being incorrectly shown as disconnected even if they are still there but the last handshake has been more than 1 minute ago.

I suggest increasing the duration to 3 minutes.

Maybe a config option that adds a PersistentKeepalive entry for the client configs could be of use as well.

Unable to load config.yaml

I've taken the config.yaml from the website and pasted that next to docker-compose.yaml. Then uncommented the line in docker-compose.yaml to copy the custom config file in.

I did have to remove a few lines as well, maybe the documentation could be updated. I removed the following from the config.yaml on the documentation.

} yaml:"wireguard"

// Rules allows you to configure what level
// of network isolation should be enfoced.

With these removed I'm able to call docker-compose up. When I do, I get the following error:
https://i.imgur.com/MPHcPmE.png

Allow rules evaluation for Gitlab

I saw that the generic OIDC feature allows evaluating rules to determine if a user is an admin or not. It would be great if the Gitlab connector also supported this feature.

Can't find user folder because OpenID token is changing

Every time the docker container is restarted, users do receive a new token from the OpenID provider. Since this token is set as 'auth/subject' and therefore used as foldername, it is not possible to list the previously created profiles for a user.

Not sure how to fix it yet, but I would suggest setting the username or email instead of idToken.Subject as 'auth/subject':

session.Put(r.Context(), "auth/subject", idToken.Subject)

Why is MySQL marked as non-ha?

I notice that mysql is marked as non-HA compatible, I was wondering why that is?

I would have thought that since every instant of the running server can access the MySQL server then it should be HA?

I would like to spin up some additional nodes but am planning to use the MySQL backend.

fatal error: thread exhaustion

I noticed wg-access-server crashed after a while on my server with this error:

runtime: program exceeds 10000-thread limit
fatal error: thread exhaustion

For now we can probably workaround it by adding this to the docker-compose.yml

    restart: always

I have attached the full log:
wg-access-server-crash.log

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.