> For the complete documentation index, see [llms.txt](https://docs.defguard.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.defguard.net/2.2/tutorials/migrating-from-defguard-1.6-to-2.0/migrating-a-1.6-one-liner-installation-to-2.x.md).

# Migrating a 1.6 one-liner installation to 2.x

{% hint style="info" %}
This guide is meant for instanced deployed using the [one-line install script](/2.2/getting-started/one-line-install.md), but the general points also apply to any other Docker Compose deployments.
{% endhint %}

Due to changes in component architecture [introduced in version 2.0](/2.2/tutorials/migrating-from-defguard-1.6-to-2.0.md) 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.

{% hint style="warning" %}
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.
{% endhint %}

Like with any upgrade, before you start make sure to [backup your data](/2.2/deployment-strategies/overview.md#backup). 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`:

```yaml
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=true
```

### Clean 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:

1. Make sure no 1.6 gateway container remains:

   ```bash
   docker ps -a
   ```
2. Check for a leftover WireGuard interface on the host (outside any container) and remove it:

   ```bash
   ip link show wg0
   sudo ip link del wg0
   ```
3. Remove the firewall table left by the 1.6 gateway, if present:

   ```bash
   sudo nft list tables
   sudo nft delete table inet DEFGUARD-wg0
   ```
4. 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 `conntrack` tool:

   ```bash
   sudo conntrack -D -p udp --dport <GATEWAY_PORT>
   ```
5. Restart the gateway:

   ```bash
   docker compose restart 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:

```yaml
# Gateway
volumes:
    - ${VOLUME_DIR:-./.volumes}/gateway/certs:/etc/defguard/certs

# Edge
volumes:
    - ${VOLUME_DIR:-./.volumes}/edge/certs:/etc/defguard/certs
```

For the Core service once the migration wizard is complete you can remove all volume mounts, since all data is stored in the database.

{% hint style="warning" %}
Don't remove the 1.6 Core service volumes before completing the migration wizard, since it also automatically migrates the RSA key setup.
{% endhint %}

## 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_SECRET`
* `DEFGUARD_GATEWAY_SECRET`
* `DEFGUARD_YUBIBRIDGE_SECRET`
* `DEFGUARD_DEFAULT_ADMIN_PASSWORD`
* `DEFGUARD_WEBAUTHN_RP_ID`
* `DEFGUARD_PROXY_GRPC_CA`
* `DEFGUARD_GRPC_KEY`
* `DEFGUARD_GRPC_CERT`

Edge/Proxy:

* `DEFGUARD_PROXY_GRPC_CERT`
* `DEFGUARD_PROXY_GRPC_KEY`
* `DEFGUARD_PROXY_URL`

Gateway:

* `DEFGUARD_GRPC_URL`
* `DEFGUARD_GRPC_CA`
* `DEFGUARD_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_KEY`
* `DEFGUARD_URL`
* `DEFGUARD_ENROLLMENT_URL`
* `DEFGUARD_PROXY_URL`
* `DEFGUARD_OPENID_KEY`, along with the `rsakey.pem` volume 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:

```
ports:
    - "50055:50055"
```

If you decide to use the [internal CA](/2.2/features/certificate-management.md) for securing HTTPS traffic, you have to expose the target HTTP and HTTPS ports:

{% hint style="warning" %}
If running on the same machine without a reverse proxy Core and Edge cannot both use the 443 host port.&#x20;

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`&#x20;
{% endhint %}

```
# Core
ports:
    - "8000:8000"
    
# Edge
ports:
    - "80:80"
    - "443:443"
```

For the gateway service the port configuration depends on the selected [network mode](#choose-the-gateway-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

{% hint style="warning" %}
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.
{% endhint %}

Pull the new images and start the stack:

```
docker compose pull 
docker compose up -d 
docker compose ps
```

Open the Core UI. Core detects the 1.6 database and starts the migration wizard. Follow [Migrating from Defguard 1.6 to 2.0](/2.2/tutorials/migrating-from-defguard-1.6-to-2.0.md) from "Review detected configuration" onwards, using the values below for the one-line deployment.

{% hint style="warning" %}
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.
{% endhint %}

#### 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](/2.2/features/certificate-management.md) and the [port summary](/2.2/deployment-strategies/hardware-os-network-and-firewall-recommendations.md#port-and-firewall-exposure-summary).

#### Gateway

When the wizard asks for the Gateway address:

* **Bridge mode:** use `gateway` and port `50066`.
* **Host mode:** the name `gateway` does 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

1. Verify the migration as described in [Verify the migration](/2.2/tutorials/migrating-from-defguard-1.6-to-2.0.md#verify-the-migration), including a VPN connection from an existing device and access to a LAN resource.
2. Back up the new `edge/certs` and `gateway/certs` directories. They hold the adoption certificates and are not stored in the database.
3. Optionally remove the post-migration variables and the Core volume mounts listed above, then run `docker compose up -d` again.
