Migrating a 1.6 one-liner installation to 2.x
Due to changes in component architecture introduced in version 2.0 an instance deployed using the one-liner script requires some manual changes to the Docker Compose config. This procedure keeps the existing database and secrets, then uses the migration wizard to adopt the 2.x Edge and Gateway.
Changing the image tags back to 1.6 is not a supported rollback. Keep the backups and old files until the migration and VPN checks pass.
Like with any upgrade, before you start make sure to backup your data. If it's possible in your environment, test the upgrade process first on a disposable test instance.
Choose the Gateway network mode
Bridge mode is the current default, but in version 1.6 the compose file generated by the one-line install script used network_mode: host.
Unless you depend on the host networking being used (due to some custom routing setup or client IP requirements for example), we encourage you to switch to bridge mode. This provides better isolation and also enables the service name DNS resolution, so Core can connect to the Gateway by simply using the gateway hostname.
To switch to bridge mode, remove the network_mode: host line and publish the WireGuard UDP port. Use the gateway port of your existing VPN location, which was chosen when the 1.6 one-line script ran, on both sides of the mapping. For example, for a location using port 51820:
ports:
- "51820:51820/udp"The gateway listens on the port set in the location settings, so if the mapping uses a different port, clients cannot complete a handshake.
If using the bridge mode you also have to enable masquerade in the gateway, otherwise responses to VPN traffic cannot be routed back to the container. To do that, add the following line to Gateway env:
DEFGUARD_MASQUERADE=trueClean up 1.6 host networking
The 1.6 gateway ran in the host network namespace and does not remove its WireGuard interface when it stops. After switching to bridge mode, a leftover interface on the host can keep receiving VPN traffic meant for the new gateway container, so clients see the port as open but no handshake completes.
After the 2.x gateway is running in bridge mode:
Make sure no 1.6 gateway container remains:
Check for a leftover WireGuard interface on the host (outside any container) and remove it:
Remove the firewall table left by the 1.6 gateway, if present:
Clear connection tracking entries for the WireGuard port. Clients send keepalive packets, so entries created while the old interface was active may never expire and keep sending traffic to it instead of the container. This requires the
conntracktool:Restart the gateway:
If you added a masquerade rule on the host for the 1.6 gateway (for example iptables -t nat -A POSTROUTING -o <interface> -j MASQUERADE), it is no longer needed in bridge mode, since DEFGUARD_MASQUERADE=true handles it inside the container. It does not conflict with the gateway, so you can remove it once VPN traffic works. If you persist host firewall rules with netfilter-persistent or iptables-restore, avoid reloading them on a running host: this flushes the rules Docker uses to forward published ports, and the WireGuard port stops reaching the container until Docker is restarted.
Update storage volumes
Since version 2.0 Defguard uses an automatic mTLS setup process to secure the communication between Core and other components (Gateway and Edge). This means that both Gateway and Edge need persistent certificate storage.
Replace the existing /ssl volume for both of them with the following mapping:
For the Core service once the migration wizard is complete you can remove all volume mounts, since all data is stored in the database.
Don't remove the 1.6 Core service volumes before completing the migration wizard, since it also automatically migrates the RSA key setup.
Remove unnecessary environment variables
Following environment variables can be removed, since they are no longer necessary in 2.0. This is a cleanup step, if left as-is these variables will not be read.
Core:
DEFGUARD_AUTH_SECRETDEFGUARD_GATEWAY_SECRETDEFGUARD_YUBIBRIDGE_SECRETDEFGUARD_DEFAULT_ADMIN_PASSWORDDEFGUARD_WEBAUTHN_RP_IDDEFGUARD_PROXY_GRPC_CADEFGUARD_GRPC_KEYDEFGUARD_GRPC_CERT
Edge/Proxy:
DEFGUARD_PROXY_GRPC_CERTDEFGUARD_PROXY_GRPC_KEYDEFGUARD_PROXY_URL
Gateway:
DEFGUARD_GRPC_URLDEFGUARD_GRPC_CADEFGUARD_TOKEN
In the .env file, you can also drop the values that only fed those variables: DEFGUARD_AUTH_SECRET, DEFGUARD_GATEWAY_SECRET, DEFGUARD_YUBIBRIDGE_SECRET, DEFGUARD_DEFAULT_ADMIN_PASSWORD, DEFGUARD_WEBAUTHN_RP_ID and DEFGUARD_TOKEN.
Once the migration wizard is complete these additional variables can also be removed from the Core service:
DEFGUARD_SECRET_KEYDEFGUARD_URLDEFGUARD_ENROLLMENT_URLDEFGUARD_PROXY_URLDEFGUARD_OPENID_KEY, along with thersakey.pemvolume mount
Update exposed ports
If you decide to keep using Caddy you can just remove the following lines from the Core service, since the communication is now reversed:
If you decide to use the internal CA for securing HTTPS traffic, you have to expose the target HTTP and HTTPS ports:
If running on the same machine without a reverse proxy Core and Edge cannot both use the 443 host port.
In the default 2.0 Compose config the Core service serves HTTP requests on port 8000 and you'll have to include this port when setting Defguard URL in the migration wizard, for example: https://defguard.example.com:8000
For the gateway service the port configuration depends on the selected network mode.
Other services
PostgreSQL database
The database service does not need to be changes.
Caddy reverse proxy
Since version 2.0 Defguard provides it's own CA and a separate reverse proxy is not required for serving the Core and Edge UI and API securely over HTTPS.
We recommend leaving Caddy as a fallback if it already works for you, but it can also be removed later.
Update image tags
At this point you can update the CORE_IMAGE_TAG, PROXY_IMAGE_TAG and GATEWAY_IMAGE_TAG environment variables to new 2.x tags.
Run the migration wizard
Before starting, confirm that the Core service does not set DEFGUARD_ADOPT_EDGE or DEFGUARD_ADOPT_GATEWAY. If either is set, Core starts the initial setup wizard instead of the migration wizard.
Pull the new images and start the stack:
Open the Core UI. Core detects the 1.6 database and starts the migration wizard. Follow Migrating from Defguard 1.6 to 2.0 from "Review detected configuration" onwards, using the values below for the one-line deployment.
For security both Edge and Gateway can be adopted by Core for 10 minutes after they start.
If more time has passed since docker compose up, restart them right before the adoption step in the wizard.
Edge
The wizard prefills the Edge address from the old Proxy settings. If you kept the proxy service name and DEFGUARD_PROXY_GRPC_PORT: 50052, use proxy and port 50052. If you renamed the service to edge or removed that variable, use the service name and port 50051.
Core and Edge URLs
If you kept Caddy, choose to keep your existing SSL setup for both Core and Edge. If you want Defguard to handle HTTPS instead, see Certificate management and the port summary.
Gateway
When the wizard asks for the Gateway address:
Bridge mode: use
gatewayand port50066.Host mode: the name
gatewaydoes not resolve, because the Gateway is not on the Compose network. Use a stable IP address of the host instead, for example its LAN IP. Make sure the address is static or reserved in DHCP. It becomes part of the Gateway's certificate and stored URL, so changing it later breaks the connection to Core.Core connects to this address from the Docker Compose network, so the host firewall must allow TCP 50066 from the Compose network's subnet. Block port 50066 everywhere else, especially on public interfaces. Until the Gateway is adopted, anyone who can reach this port can adopt it.
After the wizard completes
Verify the migration as described in Verify the migration, including a VPN connection from an existing device and access to a LAN resource.
Back up the new
edge/certsandgateway/certsdirectories. They hold the adoption certificates and are not stored in the database.Optionally remove the post-migration variables and the Core volume mounts listed above, then run
docker compose up -dagain.
Last updated
Was this helpful?