Skip to content

Custom Certificates not loaded on Android #4050

@tziuhtli

Description

@tziuhtli

The bug

In the android app, the error Failed to fetch appears upon trying to login when using a self-hosted instance with SSL certificates issued from a private Certificate Authority.

In other apps (web, linux desktop, iOS) I have managed to fix this issue by adding the certificate authority to the local certificate trust store. But on Android this does not work. I do not know how to access the logs on Android, so my guess is that the Standard Notes Android app does not trust user certificates.

To Reproduce
Steps to reproduce the behavior:

  1. Deploy self hosted using docker. See docker-compose at the end. This includes, issuing a SSL certificate for https://standardnotes.mytld.
  2. Configure DNS to point standardnotes.mytld to docker instance.
  3. Open the (self hosted) web app or any app other than the android app.
  4. Create an account. Select: email, password ,custom sync server: https://standardnotes.mytld:3000
  5. Open the android app.
  6. Select Sign In, and fill in: email, password, custom sync server as before.

Expected behavior
Android app should be able to login when using certificates signed by a custom CA. Android app should trust the certificates on the android certificate trust store, including user certificates.

Server:

  • OS: Debian Trixie
  • Docker: 29.1.2

Android:

  • OS: Android 16
  • App: 3.201.4

Docker Compose Setup

sudo curl https://raw.githubusercontent.com/standardnotes/server/main/docker/localstack_bootstrap.sh -o /home/docker/standardnotes/localstack/bootstrap.sh
sudo chmod +x /home/docker/standardnotes/localstack/bootstrap.sh 

Environment variables

DB_HOST=standardnotes_db
DB_PORT=3306
DB_USERNAME=${MYSQL_USER}
DB_PASSWORD=${MYSQL_PASSWORD}
DB_DATABASE=${MYSQL_DATABASE}
DB_TYPE=mysql
MYSQL_DATABASE=REDACTED
MYSQL_USER=REDACTED
MYSQL_ROOT_PASSWORD=REDACTED
MYSQL_PASSWORD=REDACTED
REDIS_PORT=6379
REDIS_HOST=standardnotes_cache
CACHE_TYPE=redis
AUTH_JWT_SECRET=REDACTED
AUTH_SERVER_ENCRYPTION_SERVER_KEY=REDACTED
VALET_TOKEN_SECRET=REDACTED
PUBLIC_FILES_SERVER_URL="https://standardnotes.mytld:3104"
COOKIE_DOMAIN=standardnotes.mytld

SSL
Create /etc/nginx/ssl/standardnotes.crt and /etc/nginx/ssl/standardnotes.key using the certificate authority.

Reverse Proxy Configuration

Contents of /home/docker/standardnotes/nginx/conf/standardnotes.conf.

server {
  listen 443 ssl;
  server_name standardnotes.calli;

  access_log /var/log/nginx/standardnotes-access.log;
  error_log /var/log/nginx/standardnotes-error.log;

  client_max_body_size 50M;
  
  ssl_certificate /etc/nginx/ssl/standardnotes.crt;
  ssl_certificate_key /etc/nginx/ssl/standardnotes.key;
  
  location / {
    proxy_pass http://standardnotes_app:80;
  }
}

server {
  listen 3000 ssl;
  listen [::]:3000 ssl;
  server_name standardnotes.calli;

  access_log /var/log/nginx/standardnotes-access.log;
  error_log /var/log/nginx/standardnotes-error.log;

  client_max_body_size 50M;
  
  ssl_certificate /etc/nginx/ssl/standardnotes.crt;
  ssl_certificate_key /etc/nginx/ssl/standardnotes.key;
  
  location / {
    proxy_pass http://standardnotes_api:3000;
  }
}

server {
  listen 3104 ssl;
  listen [::]:3104 ssl;
  server_name standardnotes.calli;

  access_log /var/log/nginx/standardnotes-files-access.log;
  error_log /var/log/nginx/standardnotes-files-error.log;

  client_max_body_size 50M;

  ssl_certificate /etc/nginx/ssl/standardnotes.crt;
  ssl_certificate_key /etc/nginx/ssl/standardnotes.key;

  location / {
    proxy_pass http://standardnotes_api:3104;
  }
}
services:

  standardnotes_api:
    image: standardnotes/server:latest
    container_name: standardnotes_api
    restart: unless-stopped
    volumes:
      - /home/docker/standardnotes/server/logs:/var/lib/server/logs
      - /home/docker/standardnotes/server/uploads:/opt/server/packages/files/dist/uploads
    env_file: stack.env

  localstack: # do not change. Hardcoded. There is no env var to refer to this hostname from other containers
    image: localstack/localstack:3.0
    container_name: standardnotes_localstack
    restart: unless-stopped
    volumes:
      - /home/docker/standardnotes/localstack/bootstrap.sh:/etc/localstack/init/ready.d/localstack_bootstrap.sh
    environment:
      SERVICES: sns,sqs
      LOCALSTACK_HOST: localstack # HOSTNAME_EXTERNAL to be deprecated
      LS_LOG: warn

  standardnotes_db:
    image: mysql:8
    container_name: standardnotes_db
    restart: unless-stopped
    volumes:
      - /home/docker/standardnotes/data/mysql:/var/lib/mysql
      - /home/docker/standardnotes/data/import:/docker-entrypoint-initdb.d
    env_file: stack.env

  standardnotes_cache:
    image: redis:alpine
    container_name: standardnotes_cache
    volumes:
      - /home/docker/standardnotes/data/redis:/data
    restart: unless-stopped

  standardnotes_app:
    image: standardnotes/web:latest
    container_name: standardnotes_app
    restart: unless-stopped
    environment:
      DEFAULT_SYNC_SERVER: "https://standardnotes.mytld:3000"

  nginx:
    image: nginx:alpine
    container_name: standardnotes_nginx
    restart: unless-stopped
    networks:
      default:
      macvlan:
        ipv4_address: REDACTED
    volumes:
      - /home/docker/standardnotes/nginx/conf:/etc/nginx/conf.d
      - /home/docker/standardnotes/nginx/ssl:/etc/nginx/ssl

networks:
  default:
    name: standardnotes
    ipam:
      driver: default
    driver_opts:
      com.docker.network.bridge.name: standardnotes0
  macvlan:
    name: macvlan
    external: true

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions