Setting up a ChatGPT server

I used to use the method described in my other blog to set up a ChatGPT server. It worked fantastically until April 16th when OpenAI decided that even Plus users must go through Cloudflare. (then my reverse proxy instantly died.)

Now the latest trend to bypass Cloudflare is to use undetected_chromedriver.

So here is my configuration. (many thanks to @linweiyuan)

docker compose

services:
  web:
    container_name: web
    image: kevinwang15/chatgpt-web:20230420
    ports:
      - 127.0.0.1:3055:3002
    restart: unless-stopped
    environment:
      - OPENAI_API_MODEL=gpt-4
      - API_REVERSE_PROXY=http://go-chatgpt-api:8080/chatgpt/backend-api/conversation
      - OPENAI_ACCESS_TOKEN=<get your access token from https://ai.fakeopen.com/auth>
  proxy:
    container_name: proxy
    image: kevinwang15/convert-subscription-to-http-proxy:latest
    restart: unless-stopped
    environment:
      - SUB_URL=<give me an SS subscription URL here; alternatively, remove this container and do it your own way>
  go-chatgpt-api:
    container_name: go-chatgpt-api
    image: linweiyuan/go-chatgpt-api
    ports:
      - 127.0.0.1:3056:8080
    environment:
      - TZ=Asia/Shanghai
      - GIN_MODE=release
      - PROXY=http://proxy:7890
      - ARKOSE_TOKEN_URL=http://<public-ip-of-your-server>:8199/token
    depends_on:
      - proxy
      - arkose
    restart: unless-stopped
  arkose:
    image: xyhelper/xyhelper-arkose:latest
    restart: always
    ports:
      - 8199:80
    environment:
      - PORT=80
    depends_on:
      - chrome
  chrome:
    image: kasmweb/chrome:1.10.0
    depends_on:
      - proxy
    ports:
      - "6901:6901"
    environment:
      - VNC_PW=<set up your arbitrary password here>
      - URL=http://<public-ip-of-your-server>:8199
      - http_proxy=http://proxy:7890
      - https_proxy=http://proxy:7890
    shm_size: 512m

Run with docker compose, and the ChatGPT server will listen on 127.0.0.1:3055.

Configure nginx to add SSL

map $cookie_password $is_valid_password {
    default 0;
    "your-password-here" 1;
}

server {
   listen 80;
   server_name your-site-name.com;
   return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    gzip on;
    gzip_types    text/plain application/javascript application/x-javascript text/javascript text/xml text/css;

    ssl_certificate        /etc/ssl/yoursite.crt;
    ssl_certificate_key    /etc/ssl/yoursite.key;

    server_name yoursite.com;

    location = /login {
        if ($request_method != GET) {
            return 405;
        }

        if ($arg_password = "") {
            return 400;
        }

        if ($arg_redirect = "") {
            return 400;
        }

        add_header Set-Cookie "password=$arg_password; Path=/; HttpOnly";
        return 302 $arg_redirect;
    }

    location / {
        if ($is_valid_password != 1) {
            return 401;
        }
        proxy_pass http://127.0.0.1:3055/;
        proxy_cache off;
        proxy_buffering off;
        chunked_transfer_encoding on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
    }
}

Accessing the server

You will be able to access the service through

https://yoursite.com/login?password=your-password-here&redirect=/

Monitoring

You could set up a simple cron monitor like this:

*/30 * * * * curl --retry 3 --fail -H "Authorization: Bearer $(cat /path/to/your/docker-compose.yaml | grep OPENAI_ACCESS_TOKEN | cut -d "=" -f2)" 127.0.0.1:3056/chatgpt/backend-api/conversations && curl https://healthchecks.io/ping/...

(P.S. also consider self-hosting healthchecks.io. Self-hosted healthchecks.io + Gotify is really a great cron monitoring solution especially in Mainland China)

TODO

  • Seems like Chanzhaoyu/chatgpt-web doesn’t support conversation/gen_title so the conversation title doesn’t look good. But I guess it’s not a big issue. (opened a feature request here)