[Android Kotlin] 포그라운드 서비스 (Foreground Service)

반응형

[출처] https://iamjm29.tistory.com/13

 

자세한 설명은 출처를 확인하도록 합니다.

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
http://schemas.android.com/apk/res/android"</linearlayout xmlns:android="
    xmlns:app="
http://schemas.android.com/apk/res-auto"
    xmlns:tools="
http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">

    <Button
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:text="Start Service"
        android:id="@+id/btn_start"/>

    <Button
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:text="Stop Service"
        android:id="@+id/btn_stop"/>

</LinearLayout>

 

 

AndroidManifest.xml

아래 전체를 복사하지 말고, 색칠한 곳만 참고하도록 합니다.

생성된 패키지명이 다르면 테마 이름도 다르기 때문입니다.

<?xml version="1.0" encoding="utf-8"?>
http://schemas.android.com/apk/res/android"</manifest xmlns:android="
    xmlns:tools="
http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true" />

    </application>

</manifest>

 

 

MainActivity.kt

package kr.sysdocu.test

import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    //Button
    var btn_start: Button? = null
    var btn_stop: Button? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btn_start = findViewById(R.id.btn_start)
        btn_stop = findViewById(R.id.btn_stop)

        btn_start!!.setOnClickListener(View.OnClickListener {
            val serviceIntent = Intent(this@MainActivity, MyService::class.java)
            startService(serviceIntent)
            Toast.makeText(this@MainActivity, "Service start", Toast.LENGTH_SHORT).show()
        })

        btn_stop!!.setOnClickListener(View.OnClickListener {
            val serviceIntent = Intent(this@MainActivity, MyService::class.java)
            stopService(serviceIntent)
            Toast.makeText(this@MainActivity, "Service stop", Toast.LENGTH_SHORT).show()
        })
    }
}

 


MyService.kt

package kr.sysdocu.test

import android.app.*
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat

class MyService : Service() {
    private var mThread: Thread? = null

    companion object {
        private const val TAG = "MyService"
        private const val NOTI_ID = 1
    }

    private fun createNotification() {
        val builder = NotificationCompat.Builder(this, "default")
        builder.setSmallIcon(R.mipmap.ic_launcher)
        builder.setContentTitle("Foreground Service")
        builder.setContentText("포그라운드 서비스")
        builder.color = Color.RED

        val notificationIntent = Intent(this, MainActivity::class.java)
        notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
        val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE)
        builder.setContentIntent(pendingIntent) // 알림 클릭 시 이동

        val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notificationManager.createNotificationChannel(
                NotificationChannel(
                    "default",
                    "기본 채널",
                    NotificationManager.IMPORTANCE_DEFAULT
                )
            )
        }
        val notification = builder.build()
        startForeground(NOTI_ID, notification)
    }

    override fun onCreate() {
        super.onCreate()
        createNotification()
        mThread = object : Thread("My Thread") {
            override fun run() {
                super.run()
                for (i in 0..99) {
                    Log.d(TAG, "count : $i")
                    try {
                        sleep(1000)
                    } catch (e: InterruptedException) {
                        currentThread().interrupt()
                        break
                    }
                }
            }
        }
        mThread!!.start()
        Log.d(TAG, "onCreate")
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.d(TAG, "onStartCommand")
        return START_NOT_STICKY
    }

    override fun onDestroy() {
        super.onDestroy()
        if (mThread != null) {
            mThread!!.interrupt()
            mThread = null
        }
        Log.d(TAG, "onDestroy")
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }
}

 

 

 

 

반응형

댓글()

AndroidStudio 에서 JAVA 로 GPS 현재 위치 확인하기

프로그래밍/Android (Java)|2024. 11. 1. 18:47
반응형

[출처] https://mainia.tistory.com/1153

출처에서 activity_main.xml 파일 내용만 추가하여 테스트하였고 정상 동작 확인하였습니다.

 

 

1. AndroidManifest.xml

...
    </uses-permission android:name="android.permission.internet" >
    </uses-permission android:name="android.permission.access_fine_location" >
    </uses-permission android:name="android.permission.access_coarse_location">
...

 

 

2. MainActivity.java

package kr.sysdocu.position;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

/** GPS 샘플 */
public class MainActivity extends Activity {

    private Button btnShowLocation;
    private TextView txtLat;
    private TextView txtLon;
    private final int PERMISSIONS_ACCESS_FINE_LOCATION = 1000;
    private final int PERMISSIONS_ACCESS_COARSE_LOCATION = 1001;
    private boolean isAccessFineLocation = false;
    private boolean isAccessCoarseLocation = false;
    private boolean isPermission = false;

    // GPSTracker class
    private GpsInfo gps;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnShowLocation = (Button) findViewById(R.id.btn_start);
        txtLat = (TextView) findViewById(R.id.tv_latitude);
        txtLon = (TextView) findViewById(R.id.tv_longitude);

        // GPS 정보를 보여주기 위한 이벤트 클래스 등록
        btnShowLocation.setOnClickListener(new View.OnClickListener() {
            public void onClick(View arg0) {
                // 권한 요청을 해야 함
                if (!isPermission) {
                    callPermission();
                    return;
                }

                gps = new GpsInfo(MainActivity.this);
                // GPS 사용유무 가져오기
                if (gps.isGetLocation()) {

                    double latitude = gps.getLatitude();
                    double longitude = gps.getLongitude();

                    txtLat.setText(String.valueOf(latitude));
                    txtLon.setText(String.valueOf(longitude));

                    Toast.makeText(
                            getApplicationContext(),
                            "당신의 위치 - \n위도: " + latitude + "\n경도: " + longitude,
                            Toast.LENGTH_LONG).show();
                } else {
                    // GPS 를 사용할수 없으므로
                    gps.showSettingsAlert();
                }
            }
        });

        callPermission();  // 권한 요청을 해야 함
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {
        if (requestCode == PERMISSIONS_ACCESS_FINE_LOCATION
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

            isAccessFineLocation = true;

        } else if (requestCode == PERMISSIONS_ACCESS_COARSE_LOCATION
                && grantResults[0] == PackageManager.PERMISSION_GRANTED){

            isAccessCoarseLocation = true;
        }

        if (isAccessFineLocation && isAccessCoarseLocation) {
            isPermission = true;
        }
    }

    // 전화번호 권한 요청
    private void callPermission() {
        // Check the SDK version and whether the permission is already granted or not.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {

            requestPermissions(
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_ACCESS_FINE_LOCATION);

        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED){

            requestPermissions(
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    PERMISSIONS_ACCESS_COARSE_LOCATION);
        } else {
            isPermission = true;
        }
    }
}

 

 

3. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <!-- 시작 버튼 -->
    <Button
        android:id="@+id/btn_start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="위치 가져오기" />

    <!-- 위도 표시 -->
    <TextView
        android:id="@+id/tv_latitude"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="위도: "
        android:textSize="18sp"
        android:paddingTop="20dp" />

    <!-- 경도 표시 -->
    <TextView
        android:id="@+id/tv_longitude"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="경도: "
        android:textSize="18sp"
        android:paddingTop="10dp" />

</LinearLayout>

 

 

4. GpsInfo.java

package kr.sysdocu.test;

import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import androidx.core.content.ContextCompat;

public class GpsInfo extends Service implements LocationListener {

    private final Context mContext;

    // 현재 GPS 사용유무
    boolean isGPSEnabled = false;

    // 네트워크 사용유무
    boolean isNetworkEnabled = false;

    // GPS 상태값
    boolean isGetLocation = false;

    Location location;
    double lat; // 위도
    double lon; // 경도

    // 최소 GPS 정보 업데이트 거리 10미터
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;

    // 최소 GPS 정보 업데이트 시간 밀리세컨이므로 1분
    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;

    protected LocationManager locationManager;

    public GpsInfo(Context context) {
        this.mContext = context;
        getLocation();
    }

    @TargetApi(23)
    public Location getLocation() {
        if ( Build.VERSION.SDK_INT >= 23 &&
                ContextCompat.checkSelfPermission(
                        mContext, android.Manifest.permission.ACCESS_FINE_LOCATION )
                        != PackageManager.PERMISSION_GRANTED &&
                ContextCompat.checkSelfPermission(
                        mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {

            return null;
        }

        try {
            locationManager = (LocationManager) mContext
                    .getSystemService(LOCATION_SERVICE);

            // GPS 정보 가져오기
            isGPSEnabled = locationManager
                    .isProviderEnabled(LocationManager.GPS_PROVIDER);

            // 현재 네트워크 상태 값 알아오기
            isNetworkEnabled = locationManager
                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!isGPSEnabled && !isNetworkEnabled) {
                // GPS 와 네트워크사용이 가능하지 않을때 소스 구현
            } else {
                this.isGetLocation = true;
                // 네트워크 정보로 부터 위치값 가져오기
                if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        location = locationManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            // 위도 경도 저장
                            lat = location.getLatitude();
                            lon = location.getLongitude();
                        }
                    }
                }

                if (isGPSEnabled) {
                    if (location == null) {
                        locationManager.requestLocationUpdates(
                                LocationManager.GPS_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                        if (locationManager != null) {
                            location = locationManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                lat = location.getLatitude();
                                lon = location.getLongitude();
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return location;
    }

    /**
     * GPS 종료
     * */
    public void stopUsingGPS(){
        if(locationManager != null){
            locationManager.removeUpdates(GpsInfo.this);
        }
    }

    /**
     * 위도값을 가져옵니다.
     * */
    public double getLatitude(){
        if(location != null){
            lat = location.getLatitude();
        }
        return lat;
    }

    /**
     * 경도값을 가져옵니다.
     * */
    public double getLongitude(){
        if(location != null){
            lon = location.getLongitude();
        }
        return lon;
    }

    /**
     * GPS 나 wife 정보가 켜져있는지 확인합니다.
     * */
    public boolean isGetLocation() {
        return this.isGetLocation;
    }

    /**
     * GPS 정보를 가져오지 못했을때
     * 설정값으로 갈지 물어보는 alert 창
     * */
    public void showSettingsAlert(){
        AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

        alertDialog.setTitle("GPS 사용유무셋팅");
        alertDialog.setMessage("GPS 셋팅이 되지 않았을수도 있습니다. \n 설정창으로 가시겠습니까?");

        // OK 를 누르게 되면 설정창으로 이동합니다.
        alertDialog.setPositiveButton("Settings",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,int which) {
                        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                        mContext.startActivity(intent);
                    }
                });
        // Cancle 하면 종료 합니다.
        alertDialog.setNegativeButton("Cancel",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });

        alertDialog.show();
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    public void onLocationChanged(Location location) {
        // TODO Auto-generated method stub

    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub

    }

    public void onProviderEnabled(String provider) {
        // TODO Auto-generated method stub

    }

    public void onProviderDisabled(String provider) {
        // TODO Auto-generated method stub

    }
}

 

 

 

 

 

 

 

 

반응형

댓글()

ffmpeg 명령어로 포맷 변환 예제 (mkv to mp4, mp4 to mp3)

리눅스/OS 일반|2024. 11. 1. 18:47
반응형

ffmpeg 명령으로 할 수 있는것은 다양하지만, 필자의 필요에 의해서 아래 내용만 기록해 둡니다. 

 

 

1. mkv to mp4

 

# ffmpeg -i example.mkv -c:v copy -c:a copy example.mp4

 

입력 파일 : example.mkv

출력 파일 : example.mp4

 

위 옵션 사용시 비디오 및 오디오 스트림이 원본 품질로 유지됩니다.

이 방식은 매우 빠르고 효율적이며, 데이터 손실이 없습니다.

 

 

2. mp4 to mp3

 

영상에서 오디오만 추출이 가능합니다.

 

# ffmpeg -i input.mp4 -q:a 0 -map a output.mp3

 

-i input.mp4 : 입력 MP4 파일

-q:a 0 : 오디오 품질을 최상으로 설정 (-q:a 0 대신에 -b:a 128k 와 같이 비트레이트 지정 가능)

-map a : 오디오 스트림만 추출

output.mp3 : 출력 MP3 파일 이름

 

특정 시간대의 오디오만 추출하려면 -ss (시작 시간) 와 -t (지속 시간) 를 추가합니다.

 

# ffmpeg -ss 00:01:00 -i input.mp4 -to 00:00:30 -q:a 0 -map a output.mp3

 

-ss 00:01:00 : 추출 시작 시간 (1분 0초)

-t 00:00:30 : 추출 지속 시간 (0분 30초)

-q:a 0 : 오디오 품질을 최상으로 설정 (-q:a 0 대신에 -b:a 128k 와 같이 비트레이트 지정 가능)

빠른 처리를 위해 -ss 옵션을 입력 파일 앞에 배치 하였습니다.

  이 경우, ffmpeg는 해당 시간대부터 직접 처리하므로 더욱 빠릅니다.

- mp4 말고 오디오파일 mp3 에서 부분 추출도 가능합니다.

 

반응형

댓글()

VideoJS 로 웹페이지에서 동영상 플레이어 사용하기

반응형

소스코드는 굉장히 단순합니다.

아래 옵션중 vjs-big-play-centered 는 플레이 버튼을 중앙에 두며, 미설정시 좌측 상단에 버튼이 위치합니다.

스마트폰에서 재생 버튼이 느리게 동작되어 영상을 다운로드 후 재생하는 듯 보인다면 웹서버에 H.264 모듈을 설치하여 스트리밍이 가능합니다.

 

<head>
        <meta charset="UTF-8">
        <link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.10.2/video-js.min.css" rel="stylesheet" />

        <script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.10.2/video.min.js"></script>

</head>


<body>
<video id="my-video" 

class="video-js vjs-big-play-centered

controls 

preload="auto" 

width="320

height="180

data-setup='{
"autoplay": true
}'>
        <source src="The.mkv" type='video/mp4'>

        <track kind="subtitles" src="The.vtt" srclang="ko" label="Korean" default />

</video>

</body>

 

 

* 참고 (SRT -> VTT 자막 변경 명령어)

아래 3가지만 고치면 되지만, 번거로우므로 명령어를 사용합니다.

- 시간 정보에 , (콤마) 대신 . (점)

- 자막 순번 제거

- 맨 위에 WEBVTT 라고 명시

# ffmpeg -i The.srt The.vtt

반응형

댓글()

Ubuntu 24.04 GNOME 46 Orchis 테마 적용하기

리눅스/OS 일반|2024. 9. 26. 13:53
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Ubuntu 24.04 Desktop 에서 Samsung SL-J3560FW 프린터 잡기

리눅스/OS 일반|2024. 9. 25. 09:31
반응형

프린터 설정에서 프린터를 추가할때 Samsung SL-J3560FW 모델과 동일한 드라이버가 출력되지 않고, 삼성 홈페이지에서 조차 리눅스용 드라이버를 제공하지 않습니다.

이러한 환경에서 아래 드라이버를 선택하여 설치하였더니 잘 되는 것으로 확인 했습니다.

 

- 설정 > 프린터 > [프린터 추가] > 하단 검색창에 프린터 IP 입력

 

조금 기다리면 아래 세가지 항목이 선택항목으로 출력됩니다.

-  JetDirect

- LPD

- SL-J3560FW

 

여기에서 올바른 모델명을 선택하여 진행하면 인쇄시 글씨가 깨져 출력되므로,

JetDirect 를 선택, [추가] 하고 아래 모델명을 찾아 설치합니다.

- 제조사 : Hewlett-Packard

- 드라이버 : HP Business Inkjet 110, hpcups 3.23.12

 

반응형

댓글()

간단한 리눅스 백업 스크립트 적용하기

리눅스/OS 일반|2024. 9. 19. 08:58
반응형

백업본을 저장할 디렉토리를 생성합니다.

# mkdir /backup

 

백업 스크립트를 생성합니다.

필요에 따라 아래 내용을 수정하여 사용하면 됩니다.

# vi /root/backup.sh

#!/bin/bash

# 오래된 파일 및 디렉토리 삭제
find "/backup/" -type f -mtime +5 -exec rm -f {} \;
find "/backup/" -type d -mtime +5 -exec rm -rf {} \;

# 오늘자 백업 디렉토리 생성
today=$(date +%Y%m%d)
mkdir -p /backup/${today}

# 홈페이지 소스 및 DB 백업
cd /home/sysdocu/
tar cvzf /backup/${today}/public_html.tar.gz public_html
mysqldump -uroot -p12345678 --all-databases > /backup/${today}/all.sql

# 시스템 기본 설정 파일 백업
cd /backup/${today}
cp -arp /etc/iptables/rules.v4 .
cp -arp /etc/crontab .
cp -arp /root/backup.sh .

 

# chmod 700 /root/backup.sh

 

백업 스크립트를 매일 04시에 실행되도록 스케쥴러에 등록합니다.

# echo "0 4 * * * root sh /root/backup.sh" >> /etc/crontab

 

반응형

댓글()

Ubuntu 24.04 vsftpd 설치 및 기본 설정

리눅스/FTP|2024. 9. 13. 14:44
반응형

설치는 아래와 같습니다.
# apt -y install vsftpd

시스템 계정으로 로그인하여 파일 업로드를 사용하기 위해서는 아래 옵션으로 바꿔주어야 합니다.
# vi /etc/vsftpd.conf

# 익명 접근 차단
anonymous_enable=NO

# 로컬 사용자 계정에 대한 FTP 접속 및 쓰기 허용
local_enable=YES
write_enable=YES

# 사용자 홈 디렉토리 상위 디렉토리 이동 차단
chroot_local_user=YES
allow_writeable_chroot=YES

# 패시브 모드 설정 : 지정한 포트 범위로 데이터 전송 (방화벽에 포트 추가 필요)
pasv_enable=YES
pasv_min_port=50001
pasv_max_port=50005


수정 내용은 데몬을 재시작하여 적용합니다.
# systemctl restart vsftpd

반응형

댓글()

Ubuntu 24.04 에서 APM 설치 및 Let's Encrypt SSL 적용하기 (사이트 기본 구성)

리눅스/APACHE|2024. 9. 13. 11:54
반응형

가장 기본적인 APT 패키지 관리툴로 설치를 진행합니다.

 

 

1. APM 설치

 

# apt-get -y update

# apt-get -y upgrade

# apt-get -y install apache2

# apt-get -y install php8.3 php8.3-mysql

# apt-get -y install mysql-server

# vi /etc/apache2/mods-available/mime.conf

# 아래 내용 추가
AddType application/x-httpd-php .php .htm .html
AddType application/x-httpd-php-source .phps 

 

# vi /etc/php/8.3/apache2/php.ini

; 수정 및 추가
short_open_tag = On
extension=mysqli
extension=pdo_mysql

 

# systemctl restart apache2

 


2. Virtualhost 설정

 

# cd /etc/apache2/sites-enabled

# vi default-ssl.conf

# 추가
ServerName sysdocu.kr
ServerAlias www.sysdocu.kr

 

# vi /etc/apache2/apache2.conf

# /var/www 디렉토리 설정을 찾아서 아래와 같이 수정, 디렉토리가 다를때는 추가
<Directory "/var/www/*">
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

# 404 에러 출력시 웹서버 버전 정보 숨기기
ServerSignature Off
ServerTokens Prod

 

# systemctl restart apache2

 

 

3. Let's Encrypt SSL 설정

 

# apt -y install letsencrypt

# letsencrypt certonly -a webroot --agree-tos -m admin@sysdocu.kr -w /var/www/html -d www.sysdocu.kr --rsa-key-size 4096

 

자동 갱신 설정을 합니다.

# vi /root/ssl-renew.sh

#!/bin/bash
/usr/bin/letsencrypt certonly -a webroot --agree-tos --renew-by-default -w /var/www/html -d www.sysdocu.kr
systemctl restart apache2

 

# chmod 700 /root/ssl-renew.sh

# echo "0 0 1,16 */2 * root sh /root/ssl-renew.sh" >> /etc/crontab

 

 

4. SSL 설정

 

# cd /etc/apache2/sites-enabled

# ln -s ../sites-available/default-ssl.conf .

# vi 000-default.conf

# 추가
ServerName sysdocu.kr
ServerAlias www.sysdocu.kr


# 수정
SSLCertificateFile            /etc/letsencrypt/live/www.sysdocu.kr/cert.pem
SSLCertificateKeyFile    /etc/letsencrypt/live/www.sysdocu.kr/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.sysdocu.kr/fullchain.pem 

 

# a2enmod ssl

# systemctl restart apache2

 

 

5. SSL Redirect 설정

 

# a2enmod rewrite

# systemctl restart apache2

# cd /var/www/html

# vi .htaccess

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.sysdocu.kr/$1 [R,L]

 

 

6. MySQL 설정

 

MySQL root 패스워드 설정 및 사용자 추가 방법입니다.

 

# mysql -p

(처음에는 패스워드가 없습니다. 그냥 엔터)

 

mysql> use mysql;

mysql> alter user root@localhost identified by '12345678';

mysql> flush privileges; 

 

새 데이터베이스와 계정 생성 후 권한을 부여 합니다.

mysql> create database sysdb;

mysql> create user 'sysuser'@'localhost' identified by '12345678';
mysql> grant all privileges on sysdb.* to 'sysuser'@'localhost';
mysql> flush privileges;

 

테스트를 위해 웹소스 루트 디렉토리 (/var/www/html) 에서 MySQL 계정을 이용한 접속 테스트 PHP 소스 코드를 작성합니다.

# vi test.php

<?
define("DB_HOST", "localhost");
define("DB_USER", "sysuser");
define("DB_PASSWORD", "12345678");
define("DB_NAME", "sysdb");
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if (!$conn) {
    die("Connection failed: " . mysqli_connect_error());
}

$query = "SELECT VERSION()";
$result = mysqli_query($conn, $query);
$row = mysqli_fetch_array($result);
echo "version: " . $row[0];

mysqli_close($conn);
?>

 

웹브라우저를 통해 작성한 PHP 파일에 접근하면 MySQL 과 잘 연동되고 계정이 올바를 경우 아래와 같은 메세지가 출력됩니다.

여기에서는 간단히 curl 을 이용해 테스트 해보겠습니다.

# curl https://www.sysdocu.kr/test.php

version: 8.0.39-0ubuntu0.24.04.2

 

반응형

댓글()

Ubuntu 24.04 에 Prometheus + Grafana 설치하기 (GPU 포함)

리눅스/OS 일반|2024. 9. 5. 11:43
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

RockyLinux 9 에 Prometheus + Grafana 설치하기 (GPU 포함)

리눅스/OS 일반|2024. 9. 3. 16:08
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.