Zum Inhalt springen
⚓︎ elbblick
  • Blog
  • Themen
  • Über
  • Linkbaum

Themen

Dev

  • 10. Februar 2024

    Nextcloud with Docker and NGINX on Ubuntu 22.04

    There are a ton of cloud storage providers out there including the large players: Dropbox, OneDrive, Apple Cloud and so on. Though some of these have pretty good security, the files in those storages are still accessible to the admins of said services – and in extension to governments and other third party actors.

    Do I have anything to hide? No. Do I want the government or random hackers and script kiddies looking at my personal picture archives? No again. So a self-hosted solution is the way to go.

    Enter Nextcloud, an ownCloud fork. I decided to run the Docker version behind an NGINX proxy server.

    It’s pretty simple this time, let’s jump into it!

    Step 1 – Install Docker and docker-compose

    We will use sudo, apt and apt-get for this. All these tools usually come with Ubuntu, so no need to install them. Let’s grab us some nice Docker stuff.

    # Make sure everything is up to date
    sudo apt update
    
    # Get stuff
    sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common 
    
    # Get ourselves some sweet gpg keys for docker
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    
    # Add the Docker repository
    sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
    
    # Get Docker
    sudo apt update && sudo apt-get install docker-ce docker-ce-cli containerd.io
    
    # Get docker-compose (you may need to adjust the version number, 'v2.24.5') …
    sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    # … and make it writeable
    sudo chmod +x /usr/local/bin/docker-compose

    In addition, you might need to add the server user for the website to the Docker group (and create a docker group, if not in place already):

    sudo groupadd docker
    sudo usermod -aG docker usernameobviouslyuseyourwebsiteusernamehere

    That’s all the installation stuff server-wise. Next, let’s set up NGINX.

    Step 2 – Set up NGINX

    Let’s create a configuration file for the webpage (or add a new server to an existing configuration file).

    /etc/nginx/sites-available/example.com
    server {
      server_name cloud.example.com; # Website URL
      root "/var/www/example.com/cloud.example.com"; # Website Folder
        
      location / {
        proxy_pass http://localhost:3000/; # Port as set in docker-compose (we'll do this later)
        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;
    
        client_max_body_size 0;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
    
        access_log /var/log/nginx/example.com.access.log;
        error_log /var/log/nginx/example.com.error.log;
      }
    
      location = /.well-known/carddav {
        return 301 $scheme://$host/remote.php/dav;
      }
    
      location = /.well-known/caldav {
        return 301 $scheme://$host/remote.php/dav;
      }
        
      listen 80;
    }

    At this point you’d typically make sure to add a certificate, e. g. utilising certbot --nginx to do so. I won’t cover that here.

    Step 3 – Add docker-compose.yml and db.env

    Let’s start with the docker-compose.yml file. You can copy it from here, just make sure to use a free port. 30xx should be fine. Use netstat -tunlep | grep LISTEN | awk '{print $4}' to make sure.

    version: '3'
    
    services:
      db:
        image: mariadb
        command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
        restart: always
        volumes:
          - ./db:/var/lib/mysql
        env_file:
          - db.env
    
      redis:
        image: redis
        restart: always
    
      app:
        image: nextcloud:latest
        build: ./app
        restart: always
        ports:
          - 127.0.0.1:3000:80 
          # remember the port (3000) in the nginx file? 
          # Make sure this one is the same. And it's not in use, of course.
        volumes:
          - ./nextcloud:/var/www/html
        environment:
          - MYSQL_HOST=db
        env_file:
          - db.env
        depends_on:
          - db
          - redis
    
      cron:
        build: ./app
        restart: always
        volumes:
          - ./nextcloud:/var/www/html
        entrypoint: /cron.sh
        depends_on:
          - db
          - redis
    
    volumes:
      db:
      nextcloud:

    Save and add another file, this time db.env:

    db.env
    MYSQL_ROOT_PASSWORD=UseSomeCrypticPasswordHere
    MYSQL_PASSWORD=UseAnotherCrypticPasswordHere
    MYSQL_DATABASE=nextcloud
    MYSQL_USER=nextcloud

    Step 4 – Add the Dockerfile and the redis configuration file

    Create a folder named app in your site directory, and add two files to it.

    mkdir app
    cd app
    touch Dockerfile
    touch redis.conf.php

    Add some content to those files.

    app/Dockerfile
    FROM nextcloud:apache
    COPY redis.config.php /usr/src/nextcloud/config/redis.config.php
    app/redis.config.php
    <?php
    $CONFIG = array (
      'memcache.local' => '\\OC\\Memcache\\Redis',
      'memcache.locking' => '\\OC\\Memcache\\Redis',
      'filelocking.enabled' => 'true',
      'redis' => array(
        'host' => 'redis',
        'port' => 6379,
      ),
    );

    Step 5 – Cross your fingers and …

    … run docker-compose.

    docker-compose up

    Check the output for errors. If you don’t see any, terminate the containers with Ctrl-C (once!).

    Step 6 – Fire up a detached container

    Run docker-compose again, so it starts some detached containers. Head to your website, and you should be able to follow the frontend installation process.

    docker-compose up -d

    If everything went well, you should have a running Nextcloud instance. If not, let me know and I might add more to this tutorial.

    Kommentare

  • 2. August 2023

    WordPress with NGINX, PHP-FPM and MariaDB (for MySQL) on Ubuntu 22.04

    There are a lot of ways to run WordPress. Here is the one I chose, maybe it helps you as well. If you have any questions, don’t hesitate to leave them in the comments. I will try my best to help you out. I am assuming you install this on your own server and have root access, or at least sudo access with your account.

    That being said: Let’s jump into it!

    • Step 1 – Install packages
    • Step 2 – Set up the database
    • Step 3 – Set up PHP-FPM
    • Step 4 – Install WordPress
    • Step 5 – Configure WordPress
    • Step 6 – Set up NGINX

    Step 1 – Install packages

    Before you start installing and configuring WordPress, you need to make sure you have all the tools you need. Use apt to install all the needed packages:

    sudo apt install software-properties-common
    sudo add-apt-repository -y ppa:ondrej/php
    sudo apt update
    
    sudo apt install nginx
    sudo apt install php-fpm 
    sudo apt install mariadb-server 

    Step 2 – Set up the database

    The next step is setting up the database. This should be done rather quickly. All you need to do is login to mysql.

    sudo systemctl status mariadb # check if mariadb is up and running
    sudo mariadb

    If you have set a password for mysql, use the interactive mode instead.

    sudo systemctl status mariadb # check if mariadb is up and running
    sudo mariadb -u root -p

    “Inside” we need to create a database, a user and then grant the needed privileges for the database to the generated user.

    mariadb
    CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';
    GRANT ALL PRIVILEGES ON wordpress.* TO 'user'@'localhost';
    QUIT;

    You can change the database name, user and password as you like. Make sure to jot them down, you will need them later.

    Step 3 – Set up PHP-FPM

    For this you will use PHP-FPM to handle everything php, passed on by NGINX. This utilizes a pool, for that we need to create a file in /etc/php/8.2/fpm/pool.d. Replace “8.2” with the version of php that you are using.

    php -v # find out which php-version you are using, I will use 8.2 here
    sudo vim /etc/php/8.2/fpm/pool.d/example.com.conf
    # replace <example.com> with your domain or anything you like

    In that file is the configuration for php, if used through the FastCGI Process Manager (FPM). Here is an example configuration. Remember to activate the vim insert mode by typing i, before you paste it in.

    /etc/php/8.2/fpm/pool.d/example.com.conf
    [examplecom] ; change to a unique name
    
    ; replace with the user and group of your php files:
    user = example_com
    group = example_com
    
    ; replace example-com with your domain
    listen = /run/php/example-com-fpm.sock
    
    ; should be user and group of your web server, probably leave it be:
    listen.owner = www-data 
    listen.group = www-data
    
    pm = dynamic
    pm.max_children = 120
    pm.start_servers = 12
    pm.min_spare_servers = 6
    pm.max_spare_servers = 18
    clear_env = no
    
    php_admin_value[opcache.save_comments] = 1
    php_admin_value[opcache.interned_strings_buffer] = 16
    php_admin_value[opcache.revalidate_freq] = 60
    php_admin_value[opcache.validate_timestamps] = 0
    
    env[HOSTNAME] = $HOSTNAME
    env[PATH] = /usr/local/bin:/usr/bin:/bin
    env[TMP] = /tmp
    env[TMPDIR] = /tmp
    env[TEMP] = /tmp
    
    ; you can use your domain here as well
    php_admin_value[error_log] = /var/log/fpm-php.example-com.log
    php_admin_flag[log_errors] = on
    php_admin_value[memory_limit] = 1G

    That should do it. Write to the file and exit vim by typing :wq. After that, restart PHP-FPM.

    sudo systemctl restart php8.2-fpm

    Step 4 – Install WordPress

    Change into your web root folder and create a folder for your page. Change path and folder name as needed. If you do not know how to do this, you probably should not have root access, tbh. … 😬

    mkdir /var/www/html/example.com
    cd /var/www/html/example.com

    In that folder, download wordpress and untar it.

    wget https://wordpress.org/latest.tar.gz
    tar --strip-components=1 -xvzf latest.tar.gz
    rm latest.tar.gz

    Note that --strip-components=1 strips the first part of the files’ paths, in this case the folder wordpress it would normally extract into.

    That should do it for now, next we need to configure your WordPress.

    Step 5 – Configure WordPress

    We will do this by editing the wp-config.php with our editor of choice, which of course is vim.

    cp wp-config-sample.php wp-config.php
    vim wp-config.php

    We’ll make it a short one, of course you can keep all the comments in there. If you want to put in more stuff, you can find a generator at generatewp.com.

    Link for the salt: api.wordpress.org

    wp-config.php
    <?php
    /* MySQL settings */
    define( 'DB_NAME',     'wordpress' ); // database from step 2
    define( 'DB_USER',     'user' ); // user from step 2
    define( 'DB_PASSWORD', 'password' ); // password from step 2
    define( 'DB_HOST',     'localhost' );
    define( 'DB_CHARSET',  'utf8mb4' );
    
    /* MySQL database table prefix. */
    $table_prefix = 'wp_';
    
    /* Authentication Unique Keys and Salts. */
    /* head to https://api.wordpress.org/secret-key/1.1/salt/ and copy it here */
    define('AUTH_KEY',         'I$RCe|Avd6q<^q~}r@!mwq^ds-f+{po');
    define('SECURE_AUTH_KEY',  '3.}i|OH|UEG3Ap|p#bJ+P{P%4N-WP)^');
    define('LOGGED_IN_KEY',    '0(a gw|-/d7z3T=yN)fh?WD,sWCjDD%');
    define('NONCE_KEY',        'm}(s:T%xu]gwKgwuHcThe_TEY9l7v_?');
    define('AUTH_SALT',        'JrRb)}~KaZcL5P?v|)h{m$(:m!wb9EU');
    define('SECURE_AUTH_SALT', 'enY94*k/e80(F]]_+Z}4as|B&+KX)b1');
    define('LOGGED_IN_SALT',   '=;ir6WRQj,ahn=5$? /h6|~&%0QWg=q');
    define('NONCE_SALT',       'c&hjS7e9xe{x*ip=7LoYMO@|t4d`w5B');
    
    
    /* Absolute path to the WordPress directory. */
    if ( !defined('ABSPATH') )
    	define('ABSPATH', dirname(__FILE__) . '/');
    
    /* Sets up WordPress vars and included files. */
    require_once(ABSPATH . 'wp-settings.php');

    Aaaand with that done, all we finally need to do is configure NGINX to do what it’s supposed to do.

    Step 6 – Set up nginx

    In order to do that, we are going to create a file in the sites-available folder of NGINX.

    sudo vim /etc/nginx/sites-available/example.com
    /etc/nginx/sites-available/example.com
    server {
        listen 80;
        root /var/www/html/example.com; # replace example.com
        index  index.php index.html index.htm;
        server_name  example.com; # replace example.com
    
        client_max_body_size 500M;
    
        location / {
            try_files $uri $uri/ /index.php?$args;
        }
    
        location = /favicon.ico {
            log_not_found off;
            access_log off;
        }
    
        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
            expires max;
            log_not_found off;
        }
    
        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }
    
        location ~ \.php$ {
             include snippets/fastcgi-php.conf;
             # replace example-com-fpm with socket from step 3
             fastcgi_pass unix:/var/run/php/example-com-fpm.sock;
             fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
             include fastcgi_params;
        }
    }

    Save it with :wq, link the example.com file from /etc/nginx/sites-enabled, test and restart NGINX.

    sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl restart nginx

    That’s it. Head to example.com and finish the installation from the web installer. Happy blogging!

    Edit: You still need to install a Certificate for the website, but that's not part of this post. If you need any help with that, let me know and I will add a tutorial for Let's Encrypt.

    Kommentare

  • 1. August 2023 Notiz

    Batch change permissions for folders and files

    If you ever need to change permissions for a bunch of folder and/or files without a GUI, you can utilize find and xargs to achieve that in the shell in a flash:

    find -xtype d | xargs chmod 755 # directories, standard permissions
    find -xtype f | xargs chmod 644 # files, standard permissions
    
    find -xtype d | xargs chmod 775 # directories, writeable for group
    find -xtype f | xargs chmod 664 # files, writeable for group

    Basically what we are doing here is using find to find every directory or file, depending on the type. The option xtype, followed by d or f, helps us limit the (recursive) search to directories and files respectively. xtype includes symbolic links into the results, while type would not. the resulting directory/file names are then piped into xargs, which applies the command it is followed by (here: chmod 755 and chmod 644) to the list it receives from the pipe.

    Kommentare

  • 17. Juli 2023 Notiz

    #1476107295 TYPO3\CMS\Core\Error\Exception

    I ran into a a small problem after activating the TYPO3 debug mode in my ddev TYPO3 development installation. When opening the Configuration Presets again, I was greeted with the following error:

    Screenshot of the TYPO3 install tool error box starting with “Something went wrong”. The full text follows below.

    Something went wrong
    Please use Check for broken extensions to see if a loaded extension breaks this part of the install tool and unload it.
    
    The box below may additionally reveal further details on what went wrong depending on your debug settings. It may help to temporarily switch to debug mode using Settings > Configuration Presets > Debug settings.
    
    If this error happens at an early state and no full exception back trace is shown, it may also help to manually increase debugging output in %config-dir%/system/settings.php:['BE']['debug'] => true, ['SYS']['devIPmask'] => '*', ['SYS']['displayErrors'] => 1,['SYS']['exceptionalErrors'] => 12290

    Upon investigating the Ajax error shown below the message I saw it was throwing an exception:

    Screenshot of the exception “#1476107295 TYPO3\\CMS\\Core\\Error\\Exception” with a PHP deprecation notice. The full text follows below.

    /typo3/module/tools/settings
    (1/1) #1476107295 TYPO3\CMS\Core\Error\Exception
    PHP Runtime Deprecation Notice: str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated in /var/www/html/vendor/typo3/cms-install/Classes/Configuration/Image/ImageMagick6Preset.php line 85

    Instead of increasing the debugging output as suggested, I guessed that – short of fixing the underlying function – deactivating deprecation notices would do the trick for now, hoping that the TYPO3 devs will fix this in an upcoming release. So I jumped into the console, navigated to /config/system and edited the file additional.php, and found the following lines:

    /config/system/additional.php
    'SYS' => [
    	'trustedHostsPattern' => '.*.*',
    	'devIPmask' => '*',
    	'displayErrors' => 1,
    ],

    A little addition, and everything worked out fine:

    /config/system/additional.php
    'SYS' => [
    	'trustedHostsPattern' => '.*.*',
    	'devIPmask' => '*',
    	'displayErrors' => 1,
    	'exceptionalErrors' => 8191
    ],

    I might need to adjust this, if other errors show up, but for now it’s fine. On the downside I will not catch any deprecated stuff for now, but I can live with that.

    Documentation used:

    https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/Configuration/Typo3ConfVars/SYS.html#exceptionalerrors

    https://www.php.net/manual/en/errorfunc.constants.php

    Kommentare

⚓︎ I live by the stream

  • Kontakt
  • Impressum
  • Datenschutz
  • RSS-Feed

Keine Werbung, kein Tracking-Skript. Statistik nur aus anonymisierten Server-Logs. Ein Cookie gibt es nur, wenn du dich zum Kommentieren anmeldest.

© 2026 Gerhard Wagler