3x-ui Docker & Self-Hosted Deployment

GitHub

Xray panel supporting multi-protocol multi-user expire day & traffic & IP limit (Vmess, Vless, Trojan, ShadowSocks, Wireguard, Hysteria, Tunnel, Mixed,...

44,515 stars Go Go 1 file ยท ~13,707 tokens #ech#fail2ban#http#hysteria2#mixed#mtproto#nodes#post-quantum
RAW Compose
1. Pull Image (DOCKERHUB) docker pull library/postgres
2. Docker Run (1-Click Launch) docker run -d --name 3x-ui -p 2053:2053 --restart always postgres:16-alpine
3. Podman Run podman run -d --name 3x-ui -p 2053:2053 --restart always postgres:16-alpine
4. Skopeo Inspect (Zero-Pull Manifest) skopeo inspect docker://docker.io/library/postgres:16-alpine
5. ORAS Pull (OCI Artifact) oras pull postgres:16-alpine
6. Compose Deployment docker compose up -d
docker-compose.yml
Download .yml
services:
  3xui:
    build:
      context: .
      dockerfile: ./Dockerfile
    container_name: 3xui_app
    # hostname: yourhostname <- optional
    # Optional hard memory cap. When set, the panel derives its Go soft limit
    # (GOMEMLIMIT, ~90% of this cap) so it GCs before the OOM killer fires.
    # mem_limit: 512m
    # The bundled Fail2ban (XUI_ENABLE_FAIL2BAN below) enforces the IP limit
    # with iptables, which needs NET_ADMIN. Without these caps a ban is logged
    # and shown in fail2ban status but never actually applied. NET_RAW covers
    # ip6tables. If you disable Fail2ban, you can drop cap_add.
    #
    # AmneziaWG works in this image: it runs embedded in the panel process
    # (amneziawg-go over a gVisor userspace netstack), so it needs no kernel
    # module and no host tooling. Publish its UDP listen port to use it.
    cap_add:
      - NET_ADMIN
      - NET_RAW
    volumes:
      - $PWD/db/:/etc/x-ui/
      - $PWD/cert/:/root/cert/
      # Persists acme.sh state so certificate auto-renewal survives container
      # recreation (the entrypoint re-registers the renewal cron job from it).
      - $PWD/acme/:/root/.acme.sh/
    environment:
      XRAY_VMESS_AEAD_FORCED: "false"
      XUI_ENABLE_FAIL2BAN: "true"
      # Memory tuning. The panel keeps RAM low via GOGC + periodic release; it no
      # longer sets a soft limit from total host RAM (no benefit, risks GC thrash).
      # XUI_GOGC: "75"              # lower = less RAM, slightly more CPU; GOGC env overrides
      # XUI_MEMORY_RELEASE_INTERVAL: "10"  # minutes between FreeOSMemory; 0 disables
      # Go memory soft limit, only applied from an explicit budget below (or a
      # real cgroup/mem_limit cap). Pin it with one of:
      # XUI_MEMORY_LIMIT: "400"      # in MiB
      # GOMEMLIMIT: "400MiB"         # Go syntax, takes precedence
      # XUI_PPROF: "true"           # expose pprof on 127.0.0.1:6060 for profiling
      # XUI_INIT_WEB_BASE_PATH: "/"
      # XUI_PORT: "8080"
      # To use PostgreSQL instead of the default SQLite, run:
      #   docker compose --profile postgres up -d
      # and uncomment the two lines below.
      # XUI_DB_TYPE: "postgres"
      # XUI_DB_DSN: "postgres://xui:xui@postgres:5432/xui?sslmode=disable"
    tty: true
    ports:
      # When XUI_PORT is set, publish the same container port (for example "8080:8080").
      - "2053:2053"
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    container_name: 3xui_postgres
    profiles: ["postgres"]
    environment:
      POSTGRES_USER: xui
      POSTGRES_PASSWORD: xui
      POSTGRES_DB: xui
    volumes:
      - $PWD/pgdata/:/var/lib/postgresql/data
    restart: unless-stopped