Post

Setup Linkwarden behind a reverse proxy

Setup Linkwarden behind a reverse proxy

logo

As I did not find any article explaining simply how to setup Linkwarden behind a reverse proxy, here is one to add a nginx container that serves this goal.

Setup Linkwarden

Skip this section if you already have a Linkwarden instance working.

  1. git clone the project :
    1
    2
    
    git clone https://github.com/linkwarden/linkwarden/
    cd linkwarden
    
  2. Define the secrets in the .env file :
    1
    2
    3
    
     cp .env.sample .env
     sed -i "s/POSTGRES_PASSWORD=/POSTGRES_PASSWORD=$(openssl rand -hex 32)/" .env
     sed -i "s/NEXTAUTH_SECRET=/NEXTAUTH_SECRET=$(openssl rand -hex 32)/" .env
    

    Make sure to backup this file to a safe location, as it contains the necessary credentials to access your data. Losing this file implies loss of your Linkwarden data.

  3. Start the instance :
    1
    
    docker compose up -d
    
  4. Register an account to your instance. Find the exposed port with docker ps.

  5. Shutdown your instance :
    1
    
    docker compose down
    

Setup the reverse proxy

  1. Generate the SSL certificate, if needed :
    1
    2
    3
    4
    5
    6
    7
    8
    
     DAYS_VALID=365 # 1 year, this can be increased at will
     SUBJECT="/C=US/ST=State/L=City/O=Self Hosting Inc./OU=My Solo Team/CN=Linkwarden" # change this
     CERTS_PATH="./certs"
    
     mkdir -p $CERTS_PATH
     openssl req -newkey rsa:4096 -keyout "$CERTS_PATH/server.key" -out "$CERTS_PATH/server.csr" -subj "$SUBJECT" -nodes
     openssl x509 -req -days $DAYS_VALID -in "$CERTS_PATH/server.csr" -signkey "$CERTS_PATH/server.key" -out "$CERTS_PATH/server.crt"
     rm "$CERTS_PATH/server.csr"
    
  2. Create the config files for nginx :
    1
    2
    3
    4
    5
    
     mkdir -p nginxconf/includes
     nano nginxconf/404.html
     nano nginxconf/default.conf
     nano nginxconf/includes/proxy.conf
     nano nginxconf/includes/ssl.conf
    

    Here are the files content (found in this tutorial) :

    404.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
     <html>
     <head>
     <title>Page Not Found
     </title>
     </head>
     <body>
     <h2>Proxy Backend Not Found
     </h2>
     </body>
     </html>
    

    default.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
     server {
         listen 80;
         listen 443 ssl http2;
         server_name linkwarden.test;
         ssl_certificate /etc/nginx/ssl/self.cert;
         ssl_certificate_key /etc/nginx/ssl/self-ssl.key;
         include /etc/nginx/includes/ssl.conf;
         location / {
             include /etc/nginx/includes/proxy.conf;
             proxy_pass http://linkwarden-front:3000;
         }
         access_log off;
         error_log /var/log/nginx/error.log error;
     }
     server {
         listen 80;
         server_name _;
         root /var/www/html;
         charset UTF-8;
         error_page 404 /page-not-found.html;
         location = /page-not-found.html {
             allow all;
         }
         location / {
             return 404;
         }
         access_log off;
         log_not_found off;
         error_log /var/log/nginx/error.log error;
     }
    

    proxy.conf

    1
    2
    3
    4
    5
    6
    7
    8
    
     proxy_set_header Host $host;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header X-Forwarded-Proto $scheme;
     proxy_buffering off;
     proxy_request_buffering off;
     proxy_http_version 1.1;
     proxy_intercept_errors on;
    

    ssl.conf

    1
    2
    3
    4
    
     ssl_session_timeout 1d;
     ssl_session_cache shared:SSL:50m;
     ssl_session_tickets off;
     ssl_protocols TLSv1.2 TLSv1.3;
    
  3. Edit the docker-compose.yml file :

    Edit the latest version of the file, do not copy/paste, for compatibility purpose.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    
     networks:
     linkwarden_net:
         driver: bridge
    
     services:
     postgres:
         container_name: linkwarden-postgres
         image: postgres:16-alpine
         networks:
         - linkwarden_net
         env_file: .env
         restart: always
         volumes:
         - ./pgdata:/var/lib/postgresql/data
    
     linkwarden:
         container_name: linkwarden-front
         env_file: .env
         environment:
         - DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
         restart: always
         # build: . # uncomment this line to build from source
         image: ghcr.io/linkwarden/linkwarden:latest # comment this line to build from source
         networks:
         - linkwarden_net
         # ports:
         #   - 3000
         volumes:
         - ./data:/data/data
         depends_on:
         - postgres
    
     nginx:
         container_name: linkwarden-nginx
         image: nginx:latest
         networks:
         - linkwarden_net
         ports:
         - 8443:443
         restart: always
         volumes:
         - ./certs/server.crt:/etc/nginx/ssl/self.cert:ro # this is generated by init.sh
         - ./certs/server.key:/etc/nginx/ssl/self-ssl.key:ro
         - ./nginxconf/default.conf:/etc/nginx/conf.d/default.conf:ro
         - ./nginxconf/404.html:/var/www/html/page-not-found.html:ro
         - ./nginxconf/includes/:/etc/nginx/includes/:ro
    

    Here are the change list :

    • Added nginx container (last paragraph) ;
    • Gave containers a name ;
    • Disabled exposure of html interface from the original container (port 3000).
  4. Start and test the instance. You can safely bypass the certificate warning from your browser for this case.
    1
    
     docker compose up -d
    

    The instance is running on port 8443.

Cet article est sous licence CC BY 4.0 par l'auteur.