# APISIX Readonly Proxy

# Prerequisites

Before you start following your guide you need prepare this list in advance

- <span style="white-space: pre-wrap;">Virtual Machine (VM) with </span>****Ubuntu****<span style="white-space: pre-wrap;"> Installed</span>
- <span style="white-space: pre-wrap;">SSH access and </span>****Public IP****<span style="white-space: pre-wrap;"> of that machine</span>
- <span style="white-space: pre-wrap;">Assigned Domain Name on that Public Ip e.g. - </span>****client-exante-proxy.company.com****
- <span style="white-space: pre-wrap;">Ports </span>****22, 80, 443****<span style="white-space: pre-wrap;"> should be open</span>

Bearer Token to be provided (e.g. in case of Exante)

####   
  
Generate Auth Token

#### Open a terminal window.

1. <span style="white-space: pre-wrap;">Type this command, replacing </span>`<span class="editor-theme-code">YOUR_API_KEY</span>`<span style="white-space: pre-wrap;"> and </span>`<span class="editor-theme-code">YOUR_SECRET_KEY</span>`<span style="white-space: pre-wrap;"> with your real keys:</span>  
    ```
    echo -n "YOUR_API_KEY:YOUR_SECRET_KEY" | base64
    ```
2. Press Enter.
3. The terminal will show a long string of letters and numbers. This is your encoded token.
4. Copy that string.
5. <span style="white-space: pre-wrap;">When you call your API, add this header (showing your copied string in place of </span>`<span class="editor-theme-code">ENCODED_STRING</span>`):  
    ```
    Authorization: Basic ENCODED_STRING
    ```
6. If your API really needs a Bearer header instead, use:  
    ```
    Authorization: Bearer ENCODED_STRING
    ```

That’s it. Now your API call will send the correct token.

# Installing Docker

1. ****Open Terminal****
    - Find the “Terminal” app and click it.
2. ****Run the Easy Install Command****
    - <span style="white-space: pre-wrap;">In Terminal, type or paste this whole line and press </span>****Enter****:  
        ```
        wget -qO- https://get.docker.com/ | sh
        ```
    - This downloads a small script and runs it. It will install Docker for you.
3. ****Wait for It to Finish****
    - The script will show text as it downloads and sets up Docker.
    - When the text stops, Docker is installed.
4. ****Check Docker Works****
    - Still in Terminal, type:  
        ```
        sudo docker run hello-world
        ```
    - <span style="white-space: pre-wrap;">Press </span>****Enter****. Docker will download a tiny test program and run it.
    - If you see “Hello from Docker!”, it means Docker is ready.
5. ****Let You Use Docker Without “sudo” (Optional)****
    - <span style="white-space: pre-wrap;">By default, you need to type </span>`<span class="editor-theme-code">sudo</span>`<span style="white-space: pre-wrap;"> before every Docker command. If you want to skip typing </span>`<span class="editor-theme-code">sudo</span>`, do this:
        1. Type:  
            ```
            sudo usermod -aG docker $USER
            ```
            
              
            <span style="white-space: pre-wrap;">Press </span>****Enter****.
        2. Close Terminal and log out of your Ubuntu account. Then log back in.
        3. <span style="white-space: pre-wrap;">Now you can run Docker commands without </span>`<span class="editor-theme-code">sudo</span>`. For example:  
            ```
            docker run hello-world
            ```

That’s it! Docker is now installed on your Ubuntu 22.04 in just one simple step.

# Installing APISIX

1. Open a terminal on your VM.
2. Make a folder for APISIX:  
    ```bash
    sudo mkdir -p /opt/apisix
    ```
3. <span style="white-space: pre-wrap;">Create the file </span>`<span class="editor-theme-code">/opt/apisix/apisix.yaml</span>`:  
    ```bash
    sudo nano /opt/apisix/apisix.yaml
    ```
4. <span style="white-space: pre-wrap;">Copy and paste exactly this content into </span>`<span class="editor-theme-code">apisix.yaml</span>`<span style="white-space: pre-wrap;">. Replace </span>`<span class="editor-theme-code">YOUR_BASE64_DEMO_TOKEN</span>`<span style="white-space: pre-wrap;"> and </span>`<span class="editor-theme-code">YOUR_BASE64_LIVE_TOKEN</span>`<span style="white-space: pre-wrap;"> with your real Base64(API\_KEY:SECRET\_KEY) strings:</span>  
    ```yaml
    apisix:
      node_listen: 9080  # APISIX will listen on port 9080 for HTTP
    
    consumers:
      - username: finmars  # a name for this client
        plugins:
          basic-auth:
            username: foo  # user name you want to use for APISIX basic auth
            password: bar  # password you want to use for APISIX basic auth
    
    upstreams:
      - id: 1
        nodes:
          api-demo.exante.eu:443: 1
        scheme: https
        pass_host: node
        type: roundrobin
    
      - id: 2
        nodes:
          api-live.exante.eu:443: 1
        scheme: https
        pass_host: node
        type: roundrobin
    
    plugin_configs:
      - id: 1
        plugins:
          basic-auth: {}
          proxy-rewrite:
            headers:
              set:
                # Replace this with your Base64(API_KEY:SECRET_KEY) for the demo environment
                Authorization: "Basic %TOKEN%"
            regex_uri:
              - "^/demo/(.*)"
              - "/$1"
    
      - id: 2
        plugins:
          basic-auth: {}
          proxy-rewrite:
            headers:
              set:
                # Replace this with your Base64(API_KEY:SECRET_KEY) for the live environment
                Authorization: "Basic %TOKEN%"
            regex_uri:
              - "^/live/(.*)"
              - "/$1"
    
    routes:
      - uris:
          - /demo/md/*/accounts
          - /demo/md/*/symbols/*
          - /demo/md/*/summary/*
          - /demo/md/*/ohlc/*
          - /demo/md/*/transactions
          - /demo/md/*/crossrates/*
          - /demo/trade/*/orders/*
        upstream_id: 1
        plugin_config_id: 1
    
      - uris:
          - /live/md/*/accounts
          - /live/md/*/symbols/*
          - /live/md/*/summary/*
          - /live/md/*/ohlc/*
          - /live/md/*/transactions
          - /live/md/*/crossrates/*
          - /live/trade/*/orders/*
        upstream_id: 2
        plugin_config_id: 2
    
    deployment:
      role: data_plane
      role_data_plane:
        config_provider: yaml
    
    
    #END
    ```
5. Save and close the file:
    - <span style="white-space: pre-wrap;">Press </span>`<span class="editor-theme-code">Ctrl+O</span>`<span style="white-space: pre-wrap;">, then </span>`<span class="editor-theme-code">Enter</span>`<span style="white-space: pre-wrap;"> to save.</span>
    - <span style="white-space: pre-wrap;">Press </span>`<span class="editor-theme-code">Ctrl+X</span>`<span style="white-space: pre-wrap;"> to exit Nano.</span>

---

## 2. Create a restart script for APISIX

1. In the terminal, make a new script:  
    ```bash
    nano /opt/apisix/restart_apisix.sh
    ```
2. <span style="white-space: pre-wrap;">Copy and paste this into </span>`<span class="editor-theme-code">restart_apisix.sh</span>`:  
    ```bash
    #!/bin/bash
    
    # If a container named "apache-apisix" exists, stop and remove it
    if docker ps -a --format '{{.Names}}' | grep -Eq "^apache-apisix\$"; then
      echo "Stopping and removing existing apache-apisix container..."
      docker stop apache-apisix
      docker rm apache-apisix
    fi
    
    echo "Starting a new APISIX container..."
    docker run -d \
      --name apache-apisix \
      -p 9080:9080 \
      -e APISIX_STAND_ALONE=true \
      -v /opt/apisix/apisix.yaml:/usr/local/apisix/conf/config.yaml \
      -v /opt/apisix/apisix.yaml:/usr/local/apisix/conf/apisix.yaml \
      apache/apisix
    
    echo "APISIX container is now running."
    ```
3. Save and close:
    - <span style="white-space: pre-wrap;">Press </span>`<span class="editor-theme-code">Ctrl+O</span>`<span style="white-space: pre-wrap;">, then </span>`<span class="editor-theme-code">Enter</span>`.
    - <span style="white-space: pre-wrap;">Press </span>`<span class="editor-theme-code">Ctrl+X</span>`.
4. Make the script executable:  
    ```bash
    chmod +x /opt/apisix/restart_apisix.sh
    ```

---

## 3. Run APISIX for the first time

1. In the terminal, run:  
    ```bash
    ./restart_apisix.sh
    ```
2. <span style="white-space: pre-wrap;">Wait a few seconds. APISIX will start in Docker, listening on port 9080, reading your </span>`<span class="editor-theme-code">/opt/apisix/apisix.yaml</span>`<span style="white-space: pre-wrap;"> as both </span>`<span class="editor-theme-code">config.yaml</span>`<span style="white-space: pre-wrap;"> and </span>`<span class="editor-theme-code">apisix.yaml</span>`.
3. Check that it is running:  
    ```bash
    sudo docker ps
    ```
    
      
    <span style="white-space: pre-wrap;">You should see a line for </span>`<span class="editor-theme-code">apache/apisix</span>`<span style="white-space: pre-wrap;"> with </span>`<span class="editor-theme-code">0.0.0.0:9080->9080/tcp</span>`.
4. Look at the logs to ensure no errors:  
    ```bash
    sudo docker logs apache-apisix
    ```
    
      
    You should see messages like “config file … reloaded” and no errors.

---

## 4. Test APISIX locally with curl (no Nginx yet)

1. In the terminal, run:  
    ```bash
    curl -u foo:bar http://127.0.0.1:9080/demo/md/3.0/accounts
    ```
    
    
    - `<span class="editor-theme-code">-u foo:bar</span>`<span style="white-space: pre-wrap;"> sends your Basic Auth.</span>
    - <span style="white-space: pre-wrap;">The path </span>`<span class="editor-theme-code">/demo/md/3.0/accounts</span>`<span style="white-space: pre-wrap;"> matches your route pattern </span>`<span class="editor-theme-code">/demo/md/*/accounts</span>`.
2. If everything is correct, you will see JSON returned from Exante.  
    <span style="white-space: pre-wrap;">If you see </span>`<span class="editor-theme-code">{"error_msg":"404 Route Not Found"}</span>`, double-check that the path matches exactly and that your tokens are correct.

---

# Install Nginx Proxy

## 5. Install and configure Nginx and Let’s Encrypt

### 5.1. Install Nginx

1. Update package lists:  
    ```bash
    sudo apt update
    ```
2. Install Nginx:  
    ```bash
    sudo apt install nginx -y
    ```
3. Start and enable Nginx:  
    ```bash
    sudo systemctl start nginx
    sudo systemctl enable nginx
    ```

### 5.2. Install Certbot for Let’s Encrypt

1. Add repositories and update:  
    ```bash
    sudo apt install software-properties-common -y
    sudo add-apt-repository universe
    sudo add-apt-repository ppa:certbot/certbot -y
    sudo apt update
    ```
2. Install Certbot with Nginx plugin:  
    ```bash
    sudo apt install certbot python3-certbot-nginx -y
    ```

### 5.3. Obtain a certificate for your domain

1. <span style="white-space: pre-wrap;">Make sure your DNS A record for </span>`<span class="editor-theme-code">abeta-proxy.finmars.com</span>`<span style="white-space: pre-wrap;"> points to your VM </span>`<span class="editor-theme-code">PUBLIC_IP</span>`.
2. Run:  
    ```bash
    sudo certbot --nginx -d abeta-proxy.finmars.com
    ```
3. Follow the prompts:
    1. <span style="white-space: pre-wrap;">Enter your email, then press </span>`<span class="editor-theme-code">Enter</span>`.
    2. <span style="white-space: pre-wrap;">Agree to terms by typing </span>`<span class="editor-theme-code">A</span>`<span style="white-space: pre-wrap;">, then </span>`<span class="editor-theme-code">Enter</span>`.
    3. <span style="white-space: pre-wrap;">Choose option </span>`<span class="editor-theme-code">2</span>`<span style="white-space: pre-wrap;"> to redirect HTTP to HTTPS, then </span>`<span class="editor-theme-code">Enter</span>`.

<span style="white-space: pre-wrap;">Certbot will create an Nginx site file and install the certificate under </span>`<span class="editor-theme-code">/etc/letsencrypt/live/abeta-proxy.finmars.com/</span>`.

---

## 6. Configure Nginx to proxy to APISIX

1. Open the site file Certbot created:  
    ```bash
    sudo nano /etc/nginx/sites-available/default
    ```
2. <span style="white-space: pre-wrap;">Inside the </span>`<span class="editor-theme-code">server { ... }</span>`<span style="white-space: pre-wrap;"> block for port 443, find these lines:</span>  
    ```
    listen 443 ssl;
    server_name abeta-proxy.finmars.com;
    
    ssl_certificate /etc/letsencrypt/live/abeta-proxy.finmars.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/abeta-proxy.finmars.com/privkey.pem;
    ```
3. Right below them, add:  
    ```nginx
    location / {
        proxy_pass http://127.0.0.1:9080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    ```
    
      
    <span style="white-space: pre-wrap;">After editing, that </span>`<span class="editor-theme-code">server { }</span>`<span style="white-space: pre-wrap;"> block looks like:</span>  
    ```nginx
    server {
        listen 443 ssl;
        server_name abeta-proxy.finmars.com;
    
        ssl_certificate /etc/letsencrypt/live/abeta-proxy.finmars.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/abeta-proxy.finmars.com/privkey.pem;
    
        location / {
            proxy_pass http://127.0.0.1:9080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
    ```
4. Make sure there is also a block that redirects HTTP to HTTPS. It looks like:  
    ```nginx
    server {
        listen 80;
        server_name abeta-proxy.finmars.com;
        return 301 https://$host$request_uri;
    }
    ```
5. Save and close:
    - <span style="white-space: pre-wrap;">Press </span>`<span class="editor-theme-code">Ctrl+O</span>`<span style="white-space: pre-wrap;">, then </span>`<span class="editor-theme-code">Enter</span>`.
    - <span style="white-space: pre-wrap;">Press </span>`<span class="editor-theme-code">Ctrl+X</span>`.
6. Test Nginx configuration:  
    ```bash
    sudo nginx -t
    ```
    
      
    You should see “syntax is ok” and “test is successful”.
7. Reload Nginx so it uses the new config:  
    ```bash
    sudo systemctl reload nginx
    ```

---

## 7. Open firewall ports (if you use UFW)

1. Allow HTTP (port 80) and HTTPS (port 443), and APISIX port (9080) in UFW:  
    ```bash
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw allow 9080/tcp
    ```
2. Check UFW status:  
    ```bash
    sudo ufw status
    ```

---

# Final Tests

## 8. Final tests

1. ****Test HTTPS through Nginx:****  
    In a browser or terminal, go to:  
    ```
    https://abeta-proxy.finmars.com/demo/md/3.0/accounts
    ```
    
    
    - <span style="white-space: pre-wrap;">Enter Basic Auth user </span>`<span class="editor-theme-code">foo</span>`<span style="white-space: pre-wrap;"> and password </span>`<span class="editor-theme-code">bar</span>`.
    - If your Base64 tokens are correct, you see JSON from Exante.
2. ****Test other routes:****  
    ```
    https://abeta-proxy.finmars.com/live/md/3.0/accounts
    ```
    
    
    - Use the same Basic Auth.
    - Should return JSON if live token is correct.
3. ****Test local APISIX again (no Nginx):****  
    ```
    curl -u foo:bar http://127.0.0.1:9080/demo/md/3.0/accounts
    ```
    
    
    - This hits APISIX directly, without Nginx.
    - Should return JSON if config is correct.

---

## 9. Automatic certificate renewal

1. Certbot already set up automatic renewal.
2. To test renewal, run:  
    ```bash
    sudo certbot renew --dry-run
    ```
3. If it says “Congratulations, all renewals succeeded,” your auto-renew is working.

---

## 10. How to update your APISIX config later

1. <span style="white-space: pre-wrap;">Edit </span>`<span class="editor-theme-code">/opt/apisix/apisix.yaml</span>`<span style="white-space: pre-wrap;"> any time:</span>  
    ```bash
    sudo nano /opt/apisix/apisix.yaml
    ```
2. Save changes and exit.
3. Run the restart script:  
    ```bash
    ./restart_apisix.sh
    ```
4. Check logs:  
    ```bash
    sudo docker logs apache-apisix
    ```
5. <span style="white-space: pre-wrap;">Test again with </span>`<span class="editor-theme-code">curl</span>`<span style="white-space: pre-wrap;"> or in a browser.</span>

---

# Complete Recap

### Complete Recap

1. ****Create folder****<span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">/opt/apisix</span>`.
2. ****Create and fill****<span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">/opt/apisix/apisix.yaml</span>`<span style="white-space: pre-wrap;"> (with </span>`<span class="editor-theme-code">role: data_plane</span>`<span style="white-space: pre-wrap;">, consumers, upstreams, plugin\_configs, routes, and </span>`<span class="editor-theme-code">#END</span>`).
3. ****Make****<span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">restart_apisix.sh</span>`<span style="white-space: pre-wrap;"> script that stops any old container and starts a new one, mounting </span>`<span class="editor-theme-code">/opt/apisix/apisix.yaml</span>`<span style="white-space: pre-wrap;"> as both </span>`<span class="editor-theme-code">config.yaml</span>`<span style="white-space: pre-wrap;"> and </span>`<span class="editor-theme-code">apisix.yaml</span>`.
4. ****Run****<span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">./restart_apisix.sh</span>`<span style="white-space: pre-wrap;"> to start APISIX.</span>
5. ****Test****<span style="white-space: pre-wrap;"> APISIX locally: </span>`<span class="editor-theme-code">curl -u foo:bar http://127.0.0.1:9080/demo/md/3.0/accounts</span>`.
6. ****Install Nginx****<span style="white-space: pre-wrap;"> (</span>`<span class="editor-theme-code">sudo apt install nginx</span>`).
7. ****Install Certbot****<span style="white-space: pre-wrap;"> (</span>`<span class="editor-theme-code">sudo apt install certbot python3-certbot-nginx</span>`).
8. ****Get SSL****<span style="white-space: pre-wrap;">: </span>`<span class="editor-theme-code">sudo certbot --nginx -d abeta-proxy.finmars.com</span>`.
9. ****Edit Nginx site****<span style="white-space: pre-wrap;"> at </span>`<span class="editor-theme-code">/etc/nginx/sites-available/default</span>`<span style="white-space: pre-wrap;"> to add:</span>  
    ```nginx
    location / {
        proxy_pass http://127.0.0.1:9080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    ```
10. ****Reload Nginx****<span style="white-space: pre-wrap;"> (</span>`<span class="editor-theme-code">sudo nginx -t</span>`<span style="white-space: pre-wrap;"> then </span>`<span class="editor-theme-code">sudo systemctl reload nginx</span>`).
11. ****Open firewall****<span style="white-space: pre-wrap;"> ports 80, 443, 9080 (</span>`<span class="editor-theme-code">sudo ufw allow ...</span>`).
12. ****Test****<span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">https://abeta-proxy.finmars.com/demo/md/3.0/accounts</span>`<span style="white-space: pre-wrap;"> in a browser.</span>
13. ****Auto-renew****<span style="white-space: pre-wrap;"> is handled by Certbot.</span>
14. ****To update****<span style="white-space: pre-wrap;">, edit </span>`<span class="editor-theme-code">/opt/apisix/apisix.yaml</span>`<span style="white-space: pre-wrap;"> and run </span>`<span class="editor-theme-code">./restart_apisix.sh</span>`.

That is the full, clear set of instructions. Now your APISIX runs behind Nginx with a Let’s Encrypt SSL certificate, and you can update the config anytime by editing the file and restarting with the script.