Ctrl K
ComunidadGuías…

README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
[English](README.md) | [简体中文](docs/README-zh.md) | [繁體中文](docs/README-zh-Hant.md) | [Русский](docs/README-ru.md)

# OpenVPN Server on Docker

[![Build Status](https://github.com/hwdsl2/docker-openvpn/actions/workflows/main.yml/badge.svg)](https://github.com/hwdsl2/docker-openvpn/actions/workflows/main.yml)  [![Docker Pulls](https://raw.githubusercontent.com/hwdsl2/badges/main/img/docker-pulls-openvpn-server.svg)](https://hub.docker.com/r/hwdsl2/openvpn-server)  [![License: MIT](docs/images/license.svg)](https://opensource.org/licenses/MIT)

Docker image to run an OpenVPN server. Based on Alpine Linux with OpenVPN and EasyRSA. Designed to be simple, modern, and maintainable.

**Features:**

- Automatically generates PKI, server certificates, and a client config on first start
- Client management via a helper script (`ovpn_manage`)
- Modern cipher suite: AES-128-GCM, SHA256, tls-crypt
- Dual-stack IPv4 and IPv6 support for VPN clients
- Automatically built and published via [GitHub Actions](https://github.com/hwdsl2/docker-openvpn/actions)
- Persistent data via a Docker volume
- Multi-arch: `linux/amd64`, `linux/arm64`, `linux/arm/v7`

**Also available:**

- **Without Docker:** [OpenVPN install script](https://github.com/hwdsl2/openvpn-install)
- **VPN:** [WireGuard](https://github.com/hwdsl2/docker-wireguard), [IPsec VPN](https://github.com/hwdsl2/docker-ipsec-vpn-server), [Headscale](https://github.com/hwdsl2/docker-headscale)
- **AI:** [Self-Hosted AI Stack](https://github.com/hwdsl2/self-hosted-ai-stack) for local LLMs, chat, RAG, voice and AI tools

> 📘 Interested in self-hosted AI? **The Self-Hosted AI Builder’s Guide** ([Kindle](https://books2read.com/aiguide?store=amazon) · [Google Play](https://books2read.com/aiguide?store=google) · [paperback](https://books2read.com/aiguide?store=amazon-paperback&format=PAPERBACK)) is a practical guide to building, securing, and operating your own private AI stack.

## Quick start

**Step 1.** Start the OpenVPN server:

```bash
docker run \
    --name openvpn \
    --restart=always \
    -v openvpn-data:/etc/openvpn \
    -p 1194:1194/udp \
    -d --cap-add=NET_ADMIN \
    --device=/dev/net/tun \
    --sysctl net.ipv4.ip_forward=1 \
    --sysctl net.ipv6.conf.all.forwarding=1 \
    hwdsl2/openvpn-server
```

On first start, the server automatically generates a PKI, server certificate, TLS crypt key, and a client configuration named `client.ovpn`.

**Step 2.** Copy the client configuration to your local machine:

```bash
docker cp openvpn:/etc/openvpn/clients/client.ovpn .
```

Import `client.ovpn` into your OpenVPN client to connect.

Alternatively, you may [set up OpenVPN without Docker](https://github.com/hwdsl2/openvpn-install). To learn more about how to use this image, read the sections below.

## Community

- 📬 [Get project updates and free deployment guides](https://selfhostedstack.beehiiv.com/subscribe?utm_campaign=vpn) (1–2 emails/month)
- 💬 Join the [r/selfhostedstack](https://www.reddit.com/r/selfhostedstack/) community for discussions
- ⭐ Star the repository if you find it useful — it helps others discover it

## Requirements

- A Linux server with a public IP address or DNS name
- Docker installed
- VPN port open in your firewall (UDP 1194 by default, or your configured port/protocol)

## Download

Get the trusted build from the [Docker Hub registry](https://hub.docker.com/r/hwdsl2/openvpn-server/):

```bash
docker pull hwdsl2/openvpn-server
```

Alternatively, you may download from [Quay.io](https://quay.io/repository/hwdsl2/openvpn-server):

```bash
docker pull quay.io/hwdsl2/openvpn-server
docker image tag quay.io/hwdsl2/openvpn-server hwdsl2/openvpn-server
```

Supported platforms: `linux/amd64`, `linux/arm64` and `linux/arm/v7`.

## Environment variables

All variables are optional. If not set, secure defaults are used automatically.

This Docker image uses the following variables, that can be declared in an `env` file (see [example](vpn.env.example)):

| Variable | Description | Default |
|---|---|---|
| `VPN_DNS_NAME` | Fully qualified domain name (FQDN) of the server | Auto-detected public IP |
| `VPN_PUBLIC_IP` | Public IPv4 address of the server | Auto-detected |
| `VPN_PUBLIC_IP6` | Public IPv6 address of the server | Auto-detected |
| `VPN_PROTO` | VPN protocol: `udp` or `tcp` | `udp` |
| `VPN_PORT` | VPN port (1–65535) | `1194` |
| `VPN_CLIENT_NAME` | Name of the first client config generated | `client` |
| `VPN_DNS_SRV1` | Primary DNS server pushed to clients | `8.8.8.8` |
| `VPN_DNS_SRV2` | Secondary DNS server pushed to clients | `8.8.4.4` |
| `VPN_DISABLE_USAGE_COUNTS` | Set to `1` to disable anonymous aggregate usage counts. | *(not set)* |

**Note:** In your `env` file, you may enclose values in single quotes, e.g. `VAR='value'`. Do not add spaces around `=`. If you change `VPN_PORT` or `VPN_PROTO`, update the `-p` flag in the `docker run` command accordingly.

Example using an `env` file:

```bash
docker run \
    --name openvpn \
    --restart=always \
    -v openvpn-data:/etc/openvpn \
    -v ./vpn.env:/vpn.env:ro \
    -p 1194:1194/udp \
    -d --cap-add=NET_ADMIN \
    --device=/dev/net/tun \
    --sysctl net.ipv4.ip_forward=1 \
    --sysctl net.ipv6.conf.all.forwarding=1 \
    hwdsl2/openvpn-server
```

The env file is bind-mounted into the container, so changes are picked up on every restart without recreating the container.

## Client management

Use `docker exec` to manage clients with the `ovpn_manage` helper script.

**Add a new client:**

```bash
docker exec openvpn ovpn_manage --addclient alice
docker cp openvpn:/etc/openvpn/clients/alice.ovpn .
```

**Export a client config** (prints to stdout):

```bash
docker exec openvpn ovpn_manage --exportclient alice > alice.ovpn
```

**List clients:**

```bash
docker exec openvpn ovpn_manage --listclients
```

**Revoke a client** (will prompt for confirmation):

```bash
docker exec -it openvpn ovpn_manage --revokeclient alice
# Or revoke without confirmation prompt:
docker exec openvpn ovpn_manage --revokeclient alice -y
```

## Persistent data

All server and client data is stored in the Docker volume (`/etc/openvpn` inside the container):

```
/etc/openvpn/
├── server/
│   ├── server.conf         # OpenVPN server configuration
│   ├── ca.crt              # CA certificate
│   ├── server.crt          # Server certificate
│   ├── server.key          # Server private key
│   ├── tc.key              # TLS crypt key
│   ├── dh.pem              # DH parameters
│   ├── crl.pem             # Certificate revocation list
│   ├── client-common.txt   # Client config template
│   ├── ipp.txt             # IP pool persistence
│   └── easy-rsa/pki/       # Full PKI directory
└── clients/
    ├── client.ovpn         # First client config
    └── alice.ovpn          # Additional clients
```

Back up the Docker volume to preserve all keys and client configurations.

## IPv6 support

If the Docker host has a public (global unicast) IPv6 address and the requirements below are met, IPv6 support is automatically enabled when the container starts. No manual configuration is needed.

**Requirements:**
- The Docker host must have a routable global unicast IPv6 address (starting with `2` or `3`). Link-local (`fe80::/10`) addresses are not sufficient.
- IPv6 must be enabled for the Docker container. See [Enable IPv6 support in Docker](https://docs.docker.com/engine/daemon/ipv6/).

To enable IPv6 for the Docker container, first enable IPv6 in the Docker daemon by adding the following to `/etc/docker/daemon.json` on the Docker host, then restart Docker:

```json
{
  "ipv6": true,
  "fixed-cidr-v6": "fddd:1::/64"
}
```

After that, re-create the Docker container. To verify that IPv6 is working, connect to the VPN and check your IPv6 address, e.g. using [test-ipv6.com](https://test-ipv6.com).

## Using docker-compose

```bash
cp vpn.env.example vpn.env
# Edit vpn.env if needed, then:
docker compose up -d
docker cp openvpn:/etc/openvpn/clients/client.ovpn .
```

Example `docker-compose.yml` (already included):

```yaml
services:
  openvpn:
    image: hwdsl2/openvpn-server
    container_name: openvpn
    restart: always
    ports:
      - "1194:1194/udp"
    volumes:
      - openvpn-data:/etc/openvpn
      - ./vpn.env:/vpn.env:ro
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv6.conf.all.forwarding=1

volumes:
  openvpn-data:
    name: openvpn-data
```

## Update Docker image

To update the Docker image and container, first [download](#download) the latest version:

```bash
docker pull hwdsl2/openvpn-server
```

If the Docker image is already up to date, you should see:

```
Status: Image is up to date for hwdsl2/openvpn-server:latest
```

Otherwise, it will download the latest version. Remove and re-create the container using instructions from [Quick start](#quick-start). Your data is preserved in the `openvpn-data` volume.

## Usage counts

This image uses public GitHub release asset download counts for anonymous, aggregate usage counts. Counts are approximate and are not unique users or active installs. The image does not send a telemetry payload or use a private collector. It only attempts the best-effort count after setup reaches OpenVPN startup with a mounted `/etc/openvpn` volume, and again when that persistent install first runs a different image build. To opt out, set `VPN_DISABLE_USAGE_COUNTS=1`.

## Technical details

- Base image: `alpine:3.23`
- OpenVPN: latest available from Alpine packages
- EasyRSA: bundled at build time
- Cipher: AES-128-GCM
- Auth: SHA256
- Key exchange: tls-crypt (HMAC + encrypt)
- DH parameters: pre-defined ffdhe2048 group (RFC 7919)
- Client certificates: 10-year validity
- VPN subnet: `10.8.0.0/24`
- IPv6 VPN subnet: `fddd:1194:1194:1194::/64` (when server has IPv6)

## Further reading

📚 For broader guidance on protecting your online privacy, see [Privacy Tools in the Age of AI](https://books2read.com/privacy).

## License

**Note:** The software components inside the pre-built image (such as OpenVPN and EasyRSA) are under the respective licenses chosen by their respective copyright holders. As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within.

Copyright (C) 2026 Lin Song   
This work is licensed under the [MIT License](https://opensource.org/licenses/MIT).

This project is based in part on the work of [Nyr and contributors](https://github.com/Nyr/openvpn-install), licensed under the [MIT License](https://github.com/Nyr/openvpn-install/blob/master/LICENSE).